mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	Merge pull request #5020 from jroweboy/dynamic-mf
Runtime Load MediaFoundation dlls on Windows
This commit is contained in:
		
						commit
						ddb7ead3e4
					
				
					 9 changed files with 213 additions and 6 deletions
				
			
		|  | @ -45,7 +45,9 @@ if(ENABLE_MF) | ||||||
|         hle/wmf_decoder_utils.cpp |         hle/wmf_decoder_utils.cpp | ||||||
|         hle/wmf_decoder_utils.h |         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) |     target_compile_definitions(audio_core PUBLIC HAVE_MF) | ||||||
| elseif(ENABLE_FFMPEG_AUDIO_DECODER) | elseif(ENABLE_FFMPEG_AUDIO_DECODER) | ||||||
|     target_sources(audio_core PRIVATE |     target_sources(audio_core PRIVATE | ||||||
|  |  | ||||||
|  | @ -56,6 +56,9 @@ class DecoderBase { | ||||||
| public: | public: | ||||||
|     virtual ~DecoderBase(); |     virtual ~DecoderBase(); | ||||||
|     virtual std::optional<BinaryResponse> ProcessRequest(const BinaryRequest& request) = 0; |     virtual std::optional<BinaryResponse> ProcessRequest(const BinaryRequest& request) = 0; | ||||||
|  |     /// Return true if this Decoder can be loaded. Return false if the system cannot create the
 | ||||||
|  |     /// decoder
 | ||||||
|  |     virtual bool IsValid() const = 0; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class NullDecoder final : public DecoderBase { | class NullDecoder final : public DecoderBase { | ||||||
|  | @ -63,6 +66,9 @@ public: | ||||||
|     NullDecoder(); |     NullDecoder(); | ||||||
|     ~NullDecoder() override; |     ~NullDecoder() override; | ||||||
|     std::optional<BinaryResponse> ProcessRequest(const BinaryRequest& request) override; |     std::optional<BinaryResponse> ProcessRequest(const BinaryRequest& request) override; | ||||||
|  |     bool IsValid() const override { | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace AudioCore::HLE
 | } // namespace AudioCore::HLE
 | ||||||
|  |  | ||||||
|  | @ -12,6 +12,9 @@ public: | ||||||
|     explicit Impl(Memory::MemorySystem& memory); |     explicit Impl(Memory::MemorySystem& memory); | ||||||
|     ~Impl(); |     ~Impl(); | ||||||
|     std::optional<BinaryResponse> ProcessRequest(const BinaryRequest& request); |     std::optional<BinaryResponse> ProcessRequest(const BinaryRequest& request); | ||||||
|  |     bool IsValid() const { | ||||||
|  |         return initalized; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     std::optional<BinaryResponse> Initalize(const BinaryRequest& request); |     std::optional<BinaryResponse> Initalize(const BinaryRequest& request); | ||||||
|  | @ -261,4 +264,8 @@ std::optional<BinaryResponse> FFMPEGDecoder::ProcessRequest(const BinaryRequest& | ||||||
|     return impl->ProcessRequest(request); |     return impl->ProcessRequest(request); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool FFMPEGDecoder::IsValid() const { | ||||||
|  |     return impl->IsValid(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } // namespace AudioCore::HLE
 | } // namespace AudioCore::HLE
 | ||||||
|  |  | ||||||
|  | @ -13,6 +13,7 @@ public: | ||||||
|     explicit FFMPEGDecoder(Memory::MemorySystem& memory); |     explicit FFMPEGDecoder(Memory::MemorySystem& memory); | ||||||
|     ~FFMPEGDecoder() override; |     ~FFMPEGDecoder() override; | ||||||
|     std::optional<BinaryResponse> ProcessRequest(const BinaryRequest& request) override; |     std::optional<BinaryResponse> ProcessRequest(const BinaryRequest& request) override; | ||||||
|  |     bool IsValid() const override; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     class Impl; |     class Impl; | ||||||
|  |  | ||||||
|  | @ -87,15 +87,27 @@ DspHle::Impl::Impl(DspHle& parent_, Memory::MemorySystem& memory) : parent(paren | ||||||
|         source.SetMemory(memory); |         source.SetMemory(memory); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| #ifdef HAVE_MF | #if defined(HAVE_MF) && defined(HAVE_FFMPEG) | ||||||
|     decoder = std::make_unique<HLE::WMFDecoder>(memory); |     decoder = std::make_unique<HLE::WMFDecoder>(memory); | ||||||
| #elif HAVE_FFMPEG |     if (!decoder->IsValid()) { | ||||||
|  |         LOG_WARNING(Audio_DSP, "Unable to load MediaFoundation. Attempting to load FFMPEG instead"); | ||||||
|  |         decoder = std::make_unique<HLE::FFMPEGDecoder>(memory); | ||||||
|  |     } | ||||||
|  | #elif defined(HAVE_MF) | ||||||
|  |     decoder = std::make_unique<HLE::WMFDecoder>(memory); | ||||||
|  | #elif defined(HAVE_FFMPEG) | ||||||
|     decoder = std::make_unique<HLE::FFMPEGDecoder>(memory); |     decoder = std::make_unique<HLE::FFMPEGDecoder>(memory); | ||||||
| #else | #else | ||||||
|     LOG_WARNING(Audio_DSP, "No decoder found, this could lead to missing audio"); |     LOG_WARNING(Audio_DSP, "No decoder found, this could lead to missing audio"); | ||||||
|     decoder = std::make_unique<HLE::NullDecoder>(); |     decoder = std::make_unique<HLE::NullDecoder>(); | ||||||
| #endif // HAVE_MF
 | #endif // HAVE_MF
 | ||||||
| 
 | 
 | ||||||
|  |     if (!decoder->IsValid()) { | ||||||
|  |         LOG_WARNING(Audio_DSP, | ||||||
|  |                     "Unable to load any decoders, this could cause missing audio in some games"); | ||||||
|  |         decoder = std::make_unique<HLE::NullDecoder>(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     Core::Timing& timing = Core::System::GetInstance().CoreTiming(); |     Core::Timing& timing = Core::System::GetInstance().CoreTiming(); | ||||||
|     tick_event = |     tick_event = | ||||||
|         timing.RegisterEvent("AudioCore::DspHle::tick_event", [this](u64, s64 cycles_late) { |         timing.RegisterEvent("AudioCore::DspHle::tick_event", [this](u64, s64 cycles_late) { | ||||||
|  |  | ||||||
|  | @ -7,11 +7,16 @@ | ||||||
| 
 | 
 | ||||||
| namespace AudioCore::HLE { | namespace AudioCore::HLE { | ||||||
| 
 | 
 | ||||||
|  | using namespace MFDecoder; | ||||||
|  | 
 | ||||||
| class WMFDecoder::Impl { | class WMFDecoder::Impl { | ||||||
| public: | public: | ||||||
|     explicit Impl(Memory::MemorySystem& memory); |     explicit Impl(Memory::MemorySystem& memory); | ||||||
|     ~Impl(); |     ~Impl(); | ||||||
|     std::optional<BinaryResponse> ProcessRequest(const BinaryRequest& request); |     std::optional<BinaryResponse> ProcessRequest(const BinaryRequest& request); | ||||||
|  |     bool IsValid() const { | ||||||
|  |         return is_valid; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     std::optional<BinaryResponse> Initalize(const BinaryRequest& request); |     std::optional<BinaryResponse> Initalize(const BinaryRequest& request); | ||||||
|  | @ -28,21 +33,35 @@ private: | ||||||
|     unique_mfptr<IMFTransform> transform; |     unique_mfptr<IMFTransform> transform; | ||||||
|     DWORD in_stream_id = 0; |     DWORD in_stream_id = 0; | ||||||
|     DWORD out_stream_id = 0; |     DWORD out_stream_id = 0; | ||||||
|  |     bool is_valid = false; | ||||||
|  |     bool mf_started = false; | ||||||
|  |     bool coinited = false; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| WMFDecoder::Impl::Impl(Memory::MemorySystem& memory) : memory(memory) { | 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; |     HRESULT hr = S_OK; | ||||||
|     hr = CoInitialize(NULL); |     hr = CoInitialize(NULL); | ||||||
|     // S_FALSE will be returned when COM has already been initialized
 |     // S_FALSE will be returned when COM has already been initialized
 | ||||||
|     if (hr != S_OK && hr != S_FALSE) { |     if (hr != S_OK && hr != S_FALSE) { | ||||||
|         ReportError("Failed to start COM components", hr); |         ReportError("Failed to start COM components", hr); | ||||||
|  |     } else { | ||||||
|  |         coinited = true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // lite startup is faster and all what we need is included
 |     // 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) { |     if (hr != S_OK) { | ||||||
|         // Do you know you can't initialize MF in test mode or safe mode?
 |         // Do you know you can't initialize MF in test mode or safe mode?
 | ||||||
|         ReportError("Failed to initialize Media Foundation", hr); |         ReportError("Failed to initialize Media Foundation", hr); | ||||||
|  |     } else { | ||||||
|  |         mf_started = true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     LOG_INFO(Audio_DSP, "Media Foundation activated"); |     LOG_INFO(Audio_DSP, "Media Foundation activated"); | ||||||
|  | @ -64,6 +83,7 @@ WMFDecoder::Impl::Impl(Memory::MemorySystem& memory) : memory(memory) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     transform_initialized = true; |     transform_initialized = true; | ||||||
|  |     is_valid = true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| WMFDecoder::Impl::~Impl() { | WMFDecoder::Impl::~Impl() { | ||||||
|  | @ -73,8 +93,12 @@ WMFDecoder::Impl::~Impl() { | ||||||
|         // otherwise access violation will occur
 |         // otherwise access violation will occur
 | ||||||
|         transform.reset(); |         transform.reset(); | ||||||
|     } |     } | ||||||
|     MFShutdown(); |     if (mf_started) { | ||||||
|  |         MFDecoder::MFShutdown(); | ||||||
|  |     } | ||||||
|  |     if (coinited) { | ||||||
|         CoUninitialize(); |         CoUninitialize(); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::optional<BinaryResponse> WMFDecoder::Impl::ProcessRequest(const BinaryRequest& request) { | std::optional<BinaryResponse> WMFDecoder::Impl::ProcessRequest(const BinaryRequest& request) { | ||||||
|  | @ -271,4 +295,8 @@ std::optional<BinaryResponse> WMFDecoder::ProcessRequest(const BinaryRequest& re | ||||||
|     return impl->ProcessRequest(request); |     return impl->ProcessRequest(request); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool WMFDecoder::IsValid() const { | ||||||
|  |     return impl->IsValid(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } // namespace AudioCore::HLE
 | } // namespace AudioCore::HLE
 | ||||||
|  |  | ||||||
|  | @ -13,6 +13,7 @@ public: | ||||||
|     explicit WMFDecoder(Memory::MemorySystem& memory); |     explicit WMFDecoder(Memory::MemorySystem& memory); | ||||||
|     ~WMFDecoder() override; |     ~WMFDecoder() override; | ||||||
|     std::optional<BinaryResponse> ProcessRequest(const BinaryRequest& request) override; |     std::optional<BinaryResponse> ProcessRequest(const BinaryRequest& request) override; | ||||||
|  |     bool IsValid() const override; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     class Impl; |     class Impl; | ||||||
|  |  | ||||||
|  | @ -5,6 +5,8 @@ | ||||||
| #include "common/string_util.h" | #include "common/string_util.h" | ||||||
| #include "wmf_decoder_utils.h" | #include "wmf_decoder_utils.h" | ||||||
| 
 | 
 | ||||||
|  | namespace MFDecoder { | ||||||
|  | 
 | ||||||
| // utility functions
 | // utility functions
 | ||||||
| void ReportError(std::string msg, HRESULT hr) { | void ReportError(std::string msg, HRESULT hr) { | ||||||
|     if (SUCCEEDED(hr)) { |     if (SUCCEEDED(hr)) { | ||||||
|  | @ -26,6 +28,7 @@ void ReportError(std::string msg, HRESULT hr) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| unique_mfptr<IMFTransform> MFDecoderInit(GUID audio_format) { | unique_mfptr<IMFTransform> MFDecoderInit(GUID audio_format) { | ||||||
|  | 
 | ||||||
|     HRESULT hr = S_OK; |     HRESULT hr = S_OK; | ||||||
|     MFT_REGISTER_TYPE_INFO reg = {0}; |     MFT_REGISTER_TYPE_INFO reg = {0}; | ||||||
|     GUID category = MFT_CATEGORY_AUDIO_DECODER; |     GUID category = MFT_CATEGORY_AUDIO_DECODER; | ||||||
|  | @ -347,3 +350,112 @@ std::optional<std::vector<f32>> CopySampleToBuffer(IMFSample* sample) { | ||||||
|     buffer->Unlock(); |     buffer->Unlock(); | ||||||
|     return output; |     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" | #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 MFOutputState { FatalError, OK, NeedMoreInput, NeedReconfig, HaveMoreData }; | ||||||
| enum class MFInputState { FatalError, OK, NotAccepted }; | enum class MFInputState { FatalError, OK, NotAccepted }; | ||||||
| 
 | 
 | ||||||
|  | @ -73,6 +106,9 @@ struct ADTSMeta { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| // exported functions
 | // 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<IMFTransform> MFDecoderInit(GUID audio_format = MFAudioFormat_AAC); | ||||||
| unique_mfptr<IMFSample> CreateSample(const void* data, DWORD len, DWORD alignment = 1, | unique_mfptr<IMFSample> CreateSample(const void* data, DWORD len, DWORD alignment = 1, | ||||||
|                                      LONGLONG duration = 0); |                                      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, | std::tuple<MFOutputState, unique_mfptr<IMFSample>> ReceiveSample(IMFTransform* transform, | ||||||
|                                                                  DWORD out_stream_id); |                                                                  DWORD out_stream_id); | ||||||
| std::optional<std::vector<f32>> CopySampleToBuffer(IMFSample* sample); | std::optional<std::vector<f32>> CopySampleToBuffer(IMFSample* sample); | ||||||
|  | 
 | ||||||
|  | } // namespace MFDecoder
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue