Dynamically load FFmpeg and libfdk-aac if available. (#6570)

This commit is contained in:
Steveice10 2023-06-16 16:06:18 -07:00 committed by GitHub
parent d807cdfe62
commit 38435e9b3e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 1311 additions and 877 deletions

View file

@ -2,8 +2,10 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <fdk-aac/aacdecoder_lib.h>
#include "audio_core/hle/fdk_decoder.h"
#include "common/dynamic_library/fdk-aac.h"
using namespace DynamicLibrary;
namespace AudioCore::HLE {
@ -29,13 +31,17 @@ private:
};
FDKDecoder::Impl::Impl(Memory::MemorySystem& memory) : memory(memory) {
if (!FdkAac::LoadFdkAac()) {
return;
}
// allocate an array of LIB_INFO structures
// if we don't pre-fill the whole segment with zeros, when we call `aacDecoder_GetLibInfo`
// it will segfault, upon investigation, there is some code in fdk_aac depends on your initial
// values in this array
LIB_INFO decoder_info[FDK_MODULE_LAST] = {};
// get library information and fill the struct
if (aacDecoder_GetLibInfo(decoder_info) != 0) {
if (FdkAac::aacDecoder_GetLibInfo(decoder_info) != 0) {
LOG_ERROR(Audio_DSP, "Failed to retrieve fdk_aac library information!");
return;
}
@ -44,14 +50,14 @@ FDKDecoder::Impl::Impl(Memory::MemorySystem& memory) : memory(memory) {
decoder_info[0].build_date);
// choose the input format when initializing: 1 layer of ADTS
decoder = aacDecoder_Open(TRANSPORT_TYPE::TT_MP4_ADTS, 1);
decoder = FdkAac::aacDecoder_Open(TRANSPORT_TYPE::TT_MP4_ADTS, 1);
// set maximum output channel to two (stereo)
// if the input samples have more channels, fdk_aac will perform a downmix
AAC_DECODER_ERROR ret = aacDecoder_SetParam(decoder, AAC_PCM_MAX_OUTPUT_CHANNELS, 2);
AAC_DECODER_ERROR ret = FdkAac::aacDecoder_SetParam(decoder, AAC_PCM_MAX_OUTPUT_CHANNELS, 2);
if (ret != AAC_DEC_OK) {
// unable to set this parameter reflects the decoder implementation might be broken
// we'd better shuts down everything
aacDecoder_Close(decoder);
FdkAac::aacDecoder_Close(decoder);
decoder = nullptr;
LOG_ERROR(Audio_DSP, "Unable to set downmix parameter: {}", ret);
return;
@ -73,8 +79,9 @@ std::optional<BinaryMessage> FDKDecoder::Impl::Initalize(const BinaryMessage& re
}
FDKDecoder::Impl::~Impl() {
if (decoder)
aacDecoder_Close(decoder);
if (decoder) {
FdkAac::aacDecoder_Close(decoder);
}
}
void FDKDecoder::Impl::Clear() {
@ -84,9 +91,10 @@ void FDKDecoder::Impl::Clear() {
// FLUSH - flush internal buffer
// INTR - treat the current internal buffer as discontinuous
// CONCEAL - try to interpolate and smooth out the samples
if (decoder)
aacDecoder_DecodeFrame(decoder, decoder_output, 8192,
AACDEC_FLUSH & AACDEC_INTR & AACDEC_CONCEAL);
if (decoder) {
FdkAac::aacDecoder_DecodeFrame(decoder, decoder_output, 8192,
AACDEC_FLUSH & AACDEC_INTR & AACDEC_CONCEAL);
}
}
std::optional<BinaryMessage> FDKDecoder::Impl::ProcessRequest(const BinaryMessage& request) {
@ -140,7 +148,7 @@ std::optional<BinaryMessage> FDKDecoder::Impl::Decode(const BinaryMessage& reque
std::array<std::vector<s16>, 2> out_streams;
std::size_t data_size = request.decode_aac_request.size;
u32 data_size = request.decode_aac_request.size;
// decoding loops
AAC_DECODER_ERROR result = AAC_DEC_OK;
@ -156,18 +164,18 @@ std::optional<BinaryMessage> FDKDecoder::Impl::Decode(const BinaryMessage& reque
while (buffer_remaining) {
// queue the input buffer, fdk_aac will automatically slice out the buffer it needs
// from the input buffer
result = aacDecoder_Fill(decoder, &data, &input_size, &buffer_remaining);
result = FdkAac::aacDecoder_Fill(decoder, &data, &input_size, &buffer_remaining);
if (result != AAC_DEC_OK) {
// there are some issues when queuing the input buffer
LOG_ERROR(Audio_DSP, "Failed to enqueue the input samples");
return std::nullopt;
}
// get output from decoder
result = aacDecoder_DecodeFrame(decoder, decoder_output,
sizeof(decoder_output) / sizeof(s16), 0);
result = FdkAac::aacDecoder_DecodeFrame(decoder, decoder_output,
sizeof(decoder_output) / sizeof(s16), 0);
if (result == AAC_DEC_OK) {
// get the stream information
stream_info = aacDecoder_GetStreamInfo(decoder);
stream_info = FdkAac::aacDecoder_GetStreamInfo(decoder);
// fill the stream information for binary response
response.decode_aac_response.sample_rate = GetSampleRateEnum(stream_info->sampleRate);
response.decode_aac_response.num_channels = stream_info->numChannels;

View file

@ -3,7 +3,9 @@
// Refer to the license.txt file included.
#include "audio_core/hle/ffmpeg_decoder.h"
#include "audio_core/hle/ffmpeg_dl.h"
#include "common/dynamic_library/ffmpeg.h"
using namespace DynamicLibrary;
namespace AudioCore::HLE {
@ -25,25 +27,25 @@ private:
struct AVPacketDeleter {
void operator()(AVPacket* packet) const {
av_packet_free_dl(&packet);
FFmpeg::av_packet_free(&packet);
}
};
struct AVCodecContextDeleter {
void operator()(AVCodecContext* context) const {
avcodec_free_context_dl(&context);
FFmpeg::avcodec_free_context(&context);
}
};
struct AVCodecParserContextDeleter {
void operator()(AVCodecParserContext* parser) const {
av_parser_close_dl(parser);
FFmpeg::av_parser_close(parser);
}
};
struct AVFrameDeleter {
void operator()(AVFrame* frame) const {
av_frame_free_dl(&frame);
FFmpeg::av_frame_free(&frame);
}
};
@ -60,7 +62,7 @@ private:
};
FFMPEGDecoder::Impl::Impl(Memory::MemorySystem& memory) : memory(memory) {
have_ffmpeg_dl = InitFFmpegDL();
have_ffmpeg_dl = FFmpeg::LoadFFmpeg();
}
FFMPEGDecoder::Impl::~Impl() = default;
@ -102,27 +104,27 @@ std::optional<BinaryMessage> FFMPEGDecoder::Impl::Initalize(const BinaryMessage&
return response;
}
av_packet.reset(av_packet_alloc_dl());
av_packet.reset(FFmpeg::av_packet_alloc());
codec = avcodec_find_decoder_dl(AV_CODEC_ID_AAC);
codec = FFmpeg::avcodec_find_decoder(AV_CODEC_ID_AAC);
if (!codec) {
LOG_ERROR(Audio_DSP, "Codec not found\n");
return response;
}
parser.reset(av_parser_init_dl(codec->id));
parser.reset(FFmpeg::av_parser_init(codec->id));
if (!parser) {
LOG_ERROR(Audio_DSP, "Parser not found\n");
return response;
}
av_context.reset(avcodec_alloc_context3_dl(codec));
av_context.reset(FFmpeg::avcodec_alloc_context3(codec));
if (!av_context) {
LOG_ERROR(Audio_DSP, "Could not allocate audio codec context\n");
return response;
}
if (avcodec_open2_dl(av_context.get(), codec, nullptr) < 0) {
if (FFmpeg::avcodec_open2(av_context.get(), codec, nullptr) < 0) {
LOG_ERROR(Audio_DSP, "Could not open codec\n");
return response;
}
@ -170,16 +172,16 @@ std::optional<BinaryMessage> FFMPEGDecoder::Impl::Decode(const BinaryMessage& re
std::size_t data_size = request.decode_aac_request.size;
while (data_size > 0) {
if (!decoded_frame) {
decoded_frame.reset(av_frame_alloc_dl());
decoded_frame.reset(FFmpeg::av_frame_alloc());
if (!decoded_frame) {
LOG_ERROR(Audio_DSP, "Could not allocate audio frame");
return {};
}
}
int ret =
av_parser_parse2_dl(parser.get(), av_context.get(), &av_packet->data, &av_packet->size,
data, data_size, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
int ret = FFmpeg::av_parser_parse2(parser.get(), av_context.get(), &av_packet->data,
&av_packet->size, data, static_cast<int>(data_size),
AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
if (ret < 0) {
LOG_ERROR(Audio_DSP, "Error while parsing");
return {};
@ -187,7 +189,7 @@ std::optional<BinaryMessage> FFMPEGDecoder::Impl::Decode(const BinaryMessage& re
data += ret;
data_size -= ret;
ret = avcodec_send_packet_dl(av_context.get(), av_packet.get());
ret = FFmpeg::avcodec_send_packet(av_context.get(), av_packet.get());
if (ret < 0) {
LOG_ERROR(Audio_DSP, "Error submitting the packet to the decoder");
return {};
@ -195,33 +197,39 @@ std::optional<BinaryMessage> FFMPEGDecoder::Impl::Decode(const BinaryMessage& re
if (av_packet->size) {
while (ret >= 0) {
ret = avcodec_receive_frame_dl(av_context.get(), decoded_frame.get());
ret = FFmpeg::avcodec_receive_frame(av_context.get(), decoded_frame.get());
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
break;
else if (ret < 0) {
LOG_ERROR(Audio_DSP, "Error during decoding");
return {};
}
int bytes_per_sample = av_get_bytes_per_sample_dl(av_context->sample_fmt);
int bytes_per_sample = FFmpeg::av_get_bytes_per_sample(av_context->sample_fmt);
if (bytes_per_sample < 0) {
LOG_ERROR(Audio_DSP, "Failed to calculate data size");
return {};
}
ASSERT(decoded_frame->channels <= out_streams.size());
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 24, 100)
auto num_channels = static_cast<u32>(decoded_frame->ch_layout.nb_channels);
#else
auto num_channels = static_cast<u32>(decoded_frame->channels);
#endif
ASSERT(num_channels <= out_streams.size());
std::size_t size = bytes_per_sample * (decoded_frame->nb_samples);
response.decode_aac_response.sample_rate =
GetSampleRateEnum(decoded_frame->sample_rate);
response.decode_aac_response.num_channels = decoded_frame->channels;
response.decode_aac_response.num_channels = num_channels;
response.decode_aac_response.num_samples += decoded_frame->nb_samples;
// FFmpeg converts to 32 signed floating point PCM, we need s16 PCM so we need to
// convert it
f32 val_float;
for (std::size_t current_pos(0); current_pos < size;) {
for (std::size_t channel(0); channel < decoded_frame->channels; channel++) {
for (std::size_t channel(0); channel < num_channels; channel++) {
std::memcpy(&val_float, decoded_frame->data[channel] + current_pos,
sizeof(val_float));
val_float = std::clamp(val_float, -1.0f, 1.0f);

View file

@ -1,178 +0,0 @@
// Copyright 2018 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#ifdef _WIN32
#include <memory>
#include "audio_core/hle/ffmpeg_dl.h"
#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/string_util.h"
namespace {
struct LibraryDeleter {
using pointer = HMODULE;
void operator()(HMODULE h) const {
if (h != nullptr)
FreeLibrary(h);
}
};
std::unique_ptr<HMODULE, LibraryDeleter> dll_util{nullptr};
std::unique_ptr<HMODULE, LibraryDeleter> dll_codec{nullptr};
} // namespace
FuncDL<int(AVSampleFormat)> av_get_bytes_per_sample_dl;
FuncDL<AVFrame*(void)> av_frame_alloc_dl;
FuncDL<void(AVFrame**)> av_frame_free_dl;
FuncDL<AVCodecContext*(const AVCodec*)> avcodec_alloc_context3_dl;
FuncDL<void(AVCodecContext**)> avcodec_free_context_dl;
FuncDL<int(AVCodecContext*, const AVCodec*, AVDictionary**)> avcodec_open2_dl;
FuncDL<AVPacket*(void)> av_packet_alloc_dl;
FuncDL<void(AVPacket**)> av_packet_free_dl;
FuncDL<AVCodec*(AVCodecID)> avcodec_find_decoder_dl;
FuncDL<int(AVCodecContext*, const AVPacket*)> avcodec_send_packet_dl;
FuncDL<int(AVCodecContext*, AVFrame*)> avcodec_receive_frame_dl;
FuncDL<AVCodecParserContext*(int)> av_parser_init_dl;
FuncDL<int(AVCodecParserContext*, AVCodecContext*, uint8_t**, int*, const uint8_t*, int, int64_t,
int64_t, int64_t)>
av_parser_parse2_dl;
FuncDL<void(AVCodecParserContext*)> av_parser_close_dl;
bool InitFFmpegDL() {
std::string dll_path = FileUtil::GetUserPath(FileUtil::UserPath::DLLDir);
FileUtil::CreateDir(dll_path);
std::wstring w_dll_path = Common::UTF8ToUTF16W(dll_path);
SetDllDirectoryW(w_dll_path.c_str());
dll_util.reset(LoadLibrary("avutil-56.dll"));
if (!dll_util) {
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 avutil-56.dll: {}", message);
return false;
}
dll_codec.reset(LoadLibrary("avcodec-58.dll"));
if (!dll_codec) {
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 avcodec-58.dll: {}", message);
return false;
}
av_get_bytes_per_sample_dl =
FuncDL<int(AVSampleFormat)>(dll_util.get(), "av_get_bytes_per_sample");
if (!av_get_bytes_per_sample_dl) {
LOG_ERROR(Audio_DSP, "Can not load function av_get_bytes_per_sample");
return false;
}
av_frame_alloc_dl = FuncDL<AVFrame*()>(dll_util.get(), "av_frame_alloc");
if (!av_frame_alloc_dl) {
LOG_ERROR(Audio_DSP, "Can not load function av_frame_alloc");
return false;
}
av_frame_free_dl = FuncDL<void(AVFrame**)>(dll_util.get(), "av_frame_free");
if (!av_frame_free_dl) {
LOG_ERROR(Audio_DSP, "Can not load function av_frame_free");
return false;
}
avcodec_alloc_context3_dl =
FuncDL<AVCodecContext*(const AVCodec*)>(dll_codec.get(), "avcodec_alloc_context3");
if (!avcodec_alloc_context3_dl) {
LOG_ERROR(Audio_DSP, "Can not load function avcodec_alloc_context3");
return false;
}
avcodec_free_context_dl =
FuncDL<void(AVCodecContext**)>(dll_codec.get(), "avcodec_free_context");
if (!av_get_bytes_per_sample_dl) {
LOG_ERROR(Audio_DSP, "Can not load function avcodec_free_context");
return false;
}
avcodec_open2_dl = FuncDL<int(AVCodecContext*, const AVCodec*, AVDictionary**)>(
dll_codec.get(), "avcodec_open2");
if (!avcodec_open2_dl) {
LOG_ERROR(Audio_DSP, "Can not load function avcodec_open2");
return false;
}
av_packet_alloc_dl = FuncDL<AVPacket*(void)>(dll_codec.get(), "av_packet_alloc");
if (!av_packet_alloc_dl) {
LOG_ERROR(Audio_DSP, "Can not load function av_packet_alloc");
return false;
}
av_packet_free_dl = FuncDL<void(AVPacket**)>(dll_codec.get(), "av_packet_free");
if (!av_packet_free_dl) {
LOG_ERROR(Audio_DSP, "Can not load function av_packet_free");
return false;
}
avcodec_find_decoder_dl = FuncDL<AVCodec*(AVCodecID)>(dll_codec.get(), "avcodec_find_decoder");
if (!avcodec_find_decoder_dl) {
LOG_ERROR(Audio_DSP, "Can not load function avcodec_find_decoder");
return false;
}
avcodec_send_packet_dl =
FuncDL<int(AVCodecContext*, const AVPacket*)>(dll_codec.get(), "avcodec_send_packet");
if (!avcodec_send_packet_dl) {
LOG_ERROR(Audio_DSP, "Can not load function avcodec_send_packet");
return false;
}
avcodec_receive_frame_dl =
FuncDL<int(AVCodecContext*, AVFrame*)>(dll_codec.get(), "avcodec_receive_frame");
if (!avcodec_receive_frame_dl) {
LOG_ERROR(Audio_DSP, "Can not load function avcodec_receive_frame");
return false;
}
av_parser_init_dl = FuncDL<AVCodecParserContext*(int)>(dll_codec.get(), "av_parser_init");
if (!av_parser_init_dl) {
LOG_ERROR(Audio_DSP, "Can not load function av_parser_init");
return false;
}
av_parser_parse2_dl =
FuncDL<int(AVCodecParserContext*, AVCodecContext*, uint8_t**, int*, const uint8_t*, int,
int64_t, int64_t, int64_t)>(dll_codec.get(), "av_parser_parse2");
if (!av_parser_parse2_dl) {
LOG_ERROR(Audio_DSP, "Can not load function av_parser_parse2");
return false;
}
av_parser_close_dl = FuncDL<void(AVCodecParserContext*)>(dll_codec.get(), "av_parser_close");
if (!av_parser_close_dl) {
LOG_ERROR(Audio_DSP, "Can not load function av_parser_close");
return false;
}
return true;
}
#endif // _Win32

View file

@ -1,79 +0,0 @@
// Copyright 2018 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#ifdef _WIN32
#include <windows.h>
#endif // _WIN32
extern "C" {
#include <libavcodec/avcodec.h>
}
#ifdef _WIN32
template <typename T>
struct FuncDL {
FuncDL() = default;
FuncDL(HMODULE dll, const char* name) {
if (dll) {
ptr_function = reinterpret_cast<T*>(GetProcAddress(dll, name));
}
}
operator T*() const {
return ptr_function;
}
explicit operator bool() const {
return ptr_function != nullptr;
}
T* ptr_function = nullptr;
};
extern FuncDL<int(AVSampleFormat)> av_get_bytes_per_sample_dl;
extern FuncDL<AVFrame*(void)> av_frame_alloc_dl;
extern FuncDL<void(AVFrame**)> av_frame_free_dl;
extern FuncDL<AVCodecContext*(const AVCodec*)> avcodec_alloc_context3_dl;
extern FuncDL<void(AVCodecContext**)> avcodec_free_context_dl;
extern FuncDL<int(AVCodecContext*, const AVCodec*, AVDictionary**)> avcodec_open2_dl;
extern FuncDL<AVPacket*(void)> av_packet_alloc_dl;
extern FuncDL<void(AVPacket**)> av_packet_free_dl;
extern FuncDL<AVCodec*(AVCodecID)> avcodec_find_decoder_dl;
extern FuncDL<int(AVCodecContext*, const AVPacket*)> avcodec_send_packet_dl;
extern FuncDL<int(AVCodecContext*, AVFrame*)> avcodec_receive_frame_dl;
extern FuncDL<AVCodecParserContext*(int)> av_parser_init_dl;
extern FuncDL<int(AVCodecParserContext*, AVCodecContext*, uint8_t**, int*, const uint8_t*, int,
int64_t, int64_t, int64_t)>
av_parser_parse2_dl;
extern FuncDL<void(AVCodecParserContext*)> av_parser_close_dl;
bool InitFFmpegDL();
#else // _Win32
// No dynamic loading for Unix and Apple
const auto av_get_bytes_per_sample_dl = &av_get_bytes_per_sample;
const auto av_frame_alloc_dl = &av_frame_alloc;
const auto av_frame_free_dl = &av_frame_free;
const auto avcodec_alloc_context3_dl = &avcodec_alloc_context3;
const auto avcodec_free_context_dl = &avcodec_free_context;
const auto avcodec_open2_dl = &avcodec_open2;
const auto av_packet_alloc_dl = &av_packet_alloc;
const auto av_packet_free_dl = &av_packet_free;
const auto avcodec_find_decoder_dl = &avcodec_find_decoder;
const auto avcodec_send_packet_dl = &avcodec_send_packet;
const auto avcodec_receive_frame_dl = &avcodec_receive_frame;
const auto av_parser_init_dl = &av_parser_init;
const auto av_parser_parse2_dl = &av_parser_parse2;
const auto av_parser_close_dl = &av_parser_close;
bool InitFFmpegDL() {
return true;
}
#endif // _Win32

View file

@ -12,15 +12,13 @@
#include "audio_core/hle/wmf_decoder.h"
#elif HAVE_AUDIOTOOLBOX
#include "audio_core/hle/audiotoolbox_decoder.h"
#elif HAVE_FFMPEG
#include "audio_core/hle/ffmpeg_decoder.h"
#elif ANDROID
#include "audio_core/hle/mediandk_decoder.h"
#elif HAVE_FDK
#include "audio_core/hle/fdk_decoder.h"
#endif
#include "audio_core/hle/common.h"
#include "audio_core/hle/decoder.h"
#include "audio_core/hle/fdk_decoder.h"
#include "audio_core/hle/ffmpeg_decoder.h"
#include "audio_core/hle/hle.h"
#include "audio_core/hle/mixers.h"
#include "audio_core/hle/shared_memory.h"
@ -120,6 +118,31 @@ private:
friend class boost::serialization::access;
};
static std::vector<std::function<std::unique_ptr<HLE::DecoderBase>(Memory::MemorySystem&)>>
decoder_backends = {
#if defined(HAVE_MF)
[](Memory::MemorySystem& memory) -> std::unique_ptr<HLE::DecoderBase> {
return std::make_unique<HLE::WMFDecoder>(memory);
},
#endif
#if defined(HAVE_AUDIOTOOLBOX)
[](Memory::MemorySystem& memory) -> std::unique_ptr<HLE::DecoderBase> {
return std::make_unique<HLE::AudioToolboxDecoder>(memory);
},
#endif
#if ANDROID
[](Memory::MemorySystem& memory) -> std::unique_ptr<HLE::DecoderBase> {
return std::make_unique<HLE::MediaNDKDecoder>(memory);
},
#endif
[](Memory::MemorySystem& memory) -> std::unique_ptr<HLE::DecoderBase> {
return std::make_unique<HLE::FDKDecoder>(memory);
},
[](Memory::MemorySystem& memory) -> std::unique_ptr<HLE::DecoderBase> {
return std::make_unique<HLE::FFMPEGDecoder>(memory);
},
};
DspHle::Impl::Impl(DspHle& parent_, Memory::MemorySystem& memory, Core::Timing& timing)
: parent(parent_), core_timing(timing) {
dsp_memory.raw_memory.fill(0);
@ -128,28 +151,14 @@ DspHle::Impl::Impl(DspHle& parent_, Memory::MemorySystem& memory, Core::Timing&
source.SetMemory(memory);
}
#if defined(HAVE_MF) && defined(HAVE_FFMPEG)
decoder = std::make_unique<HLE::WMFDecoder>(memory);
if (!decoder->IsValid()) {
LOG_WARNING(Audio_DSP, "Unable to load MediaFoundation. Attempting to load FFMPEG instead");
decoder = std::make_unique<HLE::FFMPEGDecoder>(memory);
for (auto& factory : decoder_backends) {
decoder = factory(memory);
if (decoder && decoder->IsValid()) {
break;
}
}
#elif defined(HAVE_MF)
decoder = std::make_unique<HLE::WMFDecoder>(memory);
#elif defined(HAVE_AUDIOTOOLBOX)
decoder = std::make_unique<HLE::AudioToolboxDecoder>(memory);
#elif defined(HAVE_FFMPEG)
decoder = std::make_unique<HLE::FFMPEGDecoder>(memory);
#elif ANDROID
decoder = std::make_unique<HLE::MediaNDKDecoder>(memory);
#elif defined(HAVE_FDK)
decoder = std::make_unique<HLE::FDKDecoder>(memory);
#else
LOG_WARNING(Audio_DSP, "No decoder found, this could lead to missing audio");
decoder = std::make_unique<HLE::NullDecoder>();
#endif // HAVE_MF
if (!decoder->IsValid()) {
if (!decoder || !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>();