Dynamically load FFmpeg and libfdk-aac if available. (#6570)
This commit is contained in:
parent
d807cdfe62
commit
38435e9b3e
38 changed files with 1311 additions and 877 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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>();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue