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

@ -65,6 +65,12 @@ add_library(citra_common STATIC
common_precompiled_headers.h
common_types.h
construct.h
dynamic_library/dynamic_library.cpp
dynamic_library/dynamic_library.h
dynamic_library/fdk-aac.cpp
dynamic_library/fdk-aac.h
dynamic_library/ffmpeg.cpp
dynamic_library/ffmpeg.h
error.cpp
error.h
file_util.cpp
@ -153,7 +159,7 @@ endif()
create_target_directory_groups(citra_common)
target_link_libraries(citra_common PUBLIC fmt::fmt microprofile Boost::boost Boost::serialization Boost::iostreams)
target_link_libraries(citra_common PUBLIC fmt::fmt library-headers microprofile Boost::boost Boost::serialization Boost::iostreams)
target_link_libraries(citra_common PRIVATE libzstd_static)
set_target_properties(citra_common PROPERTIES INTERPROCEDURAL_OPTIMIZATION ${ENABLE_LTO})

View file

@ -0,0 +1,87 @@
// Copyright 2023 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <fmt/format.h>
#if defined(_WIN32)
#include <windows.h>
#else
#include <dlfcn.h>
#endif
#include "dynamic_library.h"
namespace DynamicLibrary {
DynamicLibrary::DynamicLibrary(std::string_view name, int major, int minor) {
auto full_name = GetLibraryName(name, major, minor);
#if defined(_WIN32)
handle = reinterpret_cast<void*>(LoadLibraryA(full_name.c_str()));
if (!handle) {
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);
load_error = message;
}
#else
handle = dlopen(full_name.c_str(), RTLD_LAZY);
if (!handle) {
load_error = dlerror();
}
#endif // defined(_WIN32)
}
DynamicLibrary::~DynamicLibrary() {
if (handle) {
#if defined(_WIN32)
FreeLibrary(reinterpret_cast<HMODULE>(handle));
#else
dlclose(handle);
#endif // defined(_WIN32)
handle = nullptr;
}
}
void* DynamicLibrary::GetRawSymbol(std::string_view name) {
#if defined(_WIN32)
return reinterpret_cast<void*>(GetProcAddress(reinterpret_cast<HMODULE>(handle), name.data()));
#else
return dlsym(handle, name.data());
#endif // defined(_WIN32)
}
std::string DynamicLibrary::GetLibraryName(std::string_view name, int major, int minor) {
#if defined(_WIN32)
if (major >= 0 && minor >= 0) {
return fmt::format("{}-{}-{}.dll", name, major, minor);
} else if (major >= 0) {
return fmt::format("{}-{}.dll", name, major);
} else {
return fmt::format("{}.dll", name);
}
#elif defined(__APPLE__)
auto prefix = name.starts_with("lib") ? "" : "lib";
if (major >= 0 && minor >= 0) {
return fmt::format("{}{}.{}.{}.dylib", prefix, name, major, minor);
} else if (major >= 0) {
return fmt::format("{}{}.{}.dylib", prefix, name, major);
} else {
return fmt::format("{}{}.dylib", prefix, name);
}
#else
auto prefix = name.starts_with("lib") ? "" : "lib";
if (major >= 0 && minor >= 0) {
return fmt::format("{}{}.so.{}.{}", prefix, name, major, minor);
} else if (major >= 0) {
return fmt::format("{}{}.so.{}", prefix, name, major);
} else {
return fmt::format("{}{}.so", prefix, name);
}
#endif
}
} // namespace DynamicLibrary

View file

@ -0,0 +1,39 @@
// Copyright 2023 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <string>
#include "common/common_types.h"
namespace DynamicLibrary {
class DynamicLibrary {
public:
explicit DynamicLibrary(std::string_view name, int major = -1, int minor = -1);
~DynamicLibrary();
bool IsLoaded() {
return handle != nullptr;
}
std::string_view GetLoadError() {
return load_error;
}
template <typename T>
T GetSymbol(std::string_view name) {
return reinterpret_cast<T>(GetRawSymbol(name));
}
static std::string GetLibraryName(std::string_view name, int major = -1, int minor = -1);
private:
void* GetRawSymbol(std::string_view name);
void* handle;
std::string load_error;
};
} // namespace DynamicLibrary

View file

@ -0,0 +1,54 @@
// Copyright 2023 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/dynamic_library/fdk-aac.h"
#include "common/logging/log.h"
namespace DynamicLibrary::FdkAac {
aacDecoder_GetLibInfo_func aacDecoder_GetLibInfo;
aacDecoder_Open_func aacDecoder_Open;
aacDecoder_Close_func aacDecoder_Close;
aacDecoder_SetParam_func aacDecoder_SetParam;
aacDecoder_GetStreamInfo_func aacDecoder_GetStreamInfo;
aacDecoder_DecodeFrame_func aacDecoder_DecodeFrame;
aacDecoder_Fill_func aacDecoder_Fill;
static std::unique_ptr<DynamicLibrary> fdk_aac;
#define LOAD_SYMBOL(library, name) \
any_failed = any_failed || (name = library->GetSymbol<name##_func>(#name)) == nullptr
bool LoadFdkAac() {
if (fdk_aac) {
return true;
}
fdk_aac = std::make_unique<DynamicLibrary>("fdk-aac", 2);
if (!fdk_aac->IsLoaded()) {
LOG_WARNING(Common, "Could not dynamically load libfdk-aac: {}", fdk_aac->GetLoadError());
fdk_aac.reset();
return false;
}
auto any_failed = false;
LOAD_SYMBOL(fdk_aac, aacDecoder_GetLibInfo);
LOAD_SYMBOL(fdk_aac, aacDecoder_Open);
LOAD_SYMBOL(fdk_aac, aacDecoder_Close);
LOAD_SYMBOL(fdk_aac, aacDecoder_SetParam);
LOAD_SYMBOL(fdk_aac, aacDecoder_GetStreamInfo);
LOAD_SYMBOL(fdk_aac, aacDecoder_DecodeFrame);
LOAD_SYMBOL(fdk_aac, aacDecoder_Fill);
if (any_failed) {
LOG_WARNING(Common, "Could not find all required functions in libfdk-aac.");
fdk_aac.reset();
return false;
}
LOG_INFO(Common, "Successfully loaded libfdk-aac.");
return true;
}
} // namespace DynamicLibrary::FdkAac

View file

@ -0,0 +1,37 @@
// Copyright 2023 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
extern "C" {
#include <fdk-aac/aacdecoder_lib.h>
}
#include "common/common_types.h"
#include "common/dynamic_library/dynamic_library.h"
namespace DynamicLibrary::FdkAac {
typedef INT (*aacDecoder_GetLibInfo_func)(LIB_INFO* info);
typedef HANDLE_AACDECODER (*aacDecoder_Open_func)(TRANSPORT_TYPE transportFmt, UINT nrOfLayers);
typedef void (*aacDecoder_Close_func)(HANDLE_AACDECODER self);
typedef AAC_DECODER_ERROR (*aacDecoder_SetParam_func)(const HANDLE_AACDECODER self,
const AACDEC_PARAM param, const INT value);
typedef CStreamInfo* (*aacDecoder_GetStreamInfo_func)(HANDLE_AACDECODER self);
typedef AAC_DECODER_ERROR (*aacDecoder_DecodeFrame_func)(HANDLE_AACDECODER self, INT_PCM* pTimeData,
const INT timeDataSize, const UINT flags);
typedef AAC_DECODER_ERROR (*aacDecoder_Fill_func)(HANDLE_AACDECODER self, UCHAR* pBuffer[],
const UINT bufferSize[], UINT* bytesValid);
extern aacDecoder_GetLibInfo_func aacDecoder_GetLibInfo;
extern aacDecoder_Open_func aacDecoder_Open;
extern aacDecoder_Close_func aacDecoder_Close;
extern aacDecoder_SetParam_func aacDecoder_SetParam;
extern aacDecoder_GetStreamInfo_func aacDecoder_GetStreamInfo;
extern aacDecoder_DecodeFrame_func aacDecoder_DecodeFrame;
extern aacDecoder_Fill_func aacDecoder_Fill;
bool LoadFdkAac();
} // namespace DynamicLibrary::FdkAac

View file

@ -0,0 +1,390 @@
// Copyright 2023 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/dynamic_library/ffmpeg.h"
#include "common/logging/log.h"
namespace DynamicLibrary::FFmpeg {
// avutil
av_buffer_ref_func av_buffer_ref;
av_buffer_unref_func av_buffer_unref;
av_d2q_func av_d2q;
av_dict_count_func av_dict_count;
av_dict_get_func av_dict_get;
av_dict_get_string_func av_dict_get_string;
av_dict_set_func av_dict_set;
av_frame_alloc_func av_frame_alloc;
av_frame_free_func av_frame_free;
av_frame_unref_func av_frame_unref;
av_freep_func av_freep;
av_get_bytes_per_sample_func av_get_bytes_per_sample;
av_get_pix_fmt_func av_get_pix_fmt;
av_get_pix_fmt_name_func av_get_pix_fmt_name;
av_get_sample_fmt_name_func av_get_sample_fmt_name;
av_hwdevice_ctx_create_func av_hwdevice_ctx_create;
av_hwdevice_get_hwframe_constraints_func av_hwdevice_get_hwframe_constraints;
av_hwframe_constraints_free_func av_hwframe_constraints_free;
av_hwframe_ctx_alloc_func av_hwframe_ctx_alloc;
av_hwframe_ctx_init_func av_hwframe_ctx_init;
av_hwframe_get_buffer_func av_hwframe_get_buffer;
av_hwframe_transfer_data_func av_hwframe_transfer_data;
av_int_list_length_for_size_func av_int_list_length_for_size;
#if LIBAVCODEC_VERSION_MAJOR >= 59
av_opt_child_class_iterate_func av_opt_child_class_iterate;
#else
av_opt_child_class_next_func av_opt_child_class_next;
#endif
av_opt_next_func av_opt_next;
av_opt_set_bin_func av_opt_set_bin;
av_pix_fmt_desc_get_func av_pix_fmt_desc_get;
av_pix_fmt_desc_next_func av_pix_fmt_desc_next;
av_sample_fmt_is_planar_func av_sample_fmt_is_planar;
av_samples_alloc_array_and_samples_func av_samples_alloc_array_and_samples;
av_strdup_func av_strdup;
avutil_version_func avutil_version;
// avcodec
av_codec_is_encoder_func av_codec_is_encoder;
av_codec_iterate_func av_codec_iterate;
av_init_packet_func av_init_packet;
av_packet_alloc_func av_packet_alloc;
av_packet_free_func av_packet_free;
av_packet_rescale_ts_func av_packet_rescale_ts;
av_parser_close_func av_parser_close;
av_parser_init_func av_parser_init;
av_parser_parse2_func av_parser_parse2;
avcodec_alloc_context3_func avcodec_alloc_context3;
avcodec_descriptor_next_func avcodec_descriptor_next;
avcodec_find_decoder_func avcodec_find_decoder;
avcodec_find_encoder_by_name_func avcodec_find_encoder_by_name;
avcodec_free_context_func avcodec_free_context;
avcodec_get_class_func avcodec_get_class;
avcodec_get_hw_config_func avcodec_get_hw_config;
avcodec_open2_func avcodec_open2;
avcodec_parameters_from_context_func avcodec_parameters_from_context;
avcodec_receive_frame_func avcodec_receive_frame;
avcodec_receive_packet_func avcodec_receive_packet;
avcodec_send_frame_func avcodec_send_frame;
avcodec_send_packet_func avcodec_send_packet;
avcodec_version_func avcodec_version;
// avfilter
av_buffersink_get_frame_func av_buffersink_get_frame;
av_buffersrc_add_frame_func av_buffersrc_add_frame;
avfilter_get_by_name_func avfilter_get_by_name;
avfilter_graph_alloc_func avfilter_graph_alloc;
avfilter_graph_config_func avfilter_graph_config;
avfilter_graph_create_filter_func avfilter_graph_create_filter;
avfilter_graph_free_func avfilter_graph_free;
avfilter_graph_parse_ptr_func avfilter_graph_parse_ptr;
avfilter_inout_alloc_func avfilter_inout_alloc;
avfilter_inout_free_func avfilter_inout_free;
avfilter_version_func avfilter_version;
// avformat
av_guess_format_func av_guess_format;
av_interleaved_write_frame_func av_interleaved_write_frame;
av_muxer_iterate_func av_muxer_iterate;
av_write_trailer_func av_write_trailer;
avformat_alloc_output_context2_func avformat_alloc_output_context2;
avformat_free_context_func avformat_free_context;
avformat_get_class_func avformat_get_class;
avformat_network_init_func avformat_network_init;
avformat_new_stream_func avformat_new_stream;
avformat_query_codec_func avformat_query_codec;
avformat_write_header_func avformat_write_header;
avformat_version_func avformat_version;
avio_closep_func avio_closep;
avio_open_func avio_open;
// swresample
#if LIBSWRESAMPLE_VERSION_INT >= AV_VERSION_INT(4, 5, 100)
swr_alloc_set_opts2_func swr_alloc_set_opts2;
#else
swr_alloc_set_opts_func swr_alloc_set_opts;
#endif
swr_convert_func swr_convert;
swr_free_func swr_free;
swr_init_func swr_init;
swresample_version_func swresample_version;
static std::unique_ptr<DynamicLibrary> avutil;
static std::unique_ptr<DynamicLibrary> avcodec;
static std::unique_ptr<DynamicLibrary> avfilter;
static std::unique_ptr<DynamicLibrary> avformat;
static std::unique_ptr<DynamicLibrary> swresample;
#define LOAD_SYMBOL(library, name) \
any_failed = any_failed || (name = library->GetSymbol<name##_func>(#name)) == nullptr
static bool LoadAVUtil() {
if (avutil) {
return true;
}
avutil = std::make_unique<DynamicLibrary>("avutil", LIBAVUTIL_VERSION_MAJOR);
if (!avutil->IsLoaded()) {
LOG_WARNING(Common, "Could not dynamically load libavutil: {}", avutil->GetLoadError());
avutil.reset();
return false;
}
auto any_failed = false;
LOAD_SYMBOL(avutil, avutil_version);
auto major_version = AV_VERSION_MAJOR(avutil_version());
if (major_version != LIBAVUTIL_VERSION_MAJOR) {
LOG_WARNING(Common, "libavutil version {} does not match supported version {}.",
major_version, LIBAVUTIL_VERSION_MAJOR);
avutil.reset();
return false;
}
LOAD_SYMBOL(avutil, av_buffer_ref);
LOAD_SYMBOL(avutil, av_buffer_unref);
LOAD_SYMBOL(avutil, av_d2q);
LOAD_SYMBOL(avutil, av_dict_count);
LOAD_SYMBOL(avutil, av_dict_get);
LOAD_SYMBOL(avutil, av_dict_get_string);
LOAD_SYMBOL(avutil, av_dict_set);
LOAD_SYMBOL(avutil, av_frame_alloc);
LOAD_SYMBOL(avutil, av_frame_free);
LOAD_SYMBOL(avutil, av_frame_unref);
LOAD_SYMBOL(avutil, av_freep);
LOAD_SYMBOL(avutil, av_get_bytes_per_sample);
LOAD_SYMBOL(avutil, av_get_pix_fmt);
LOAD_SYMBOL(avutil, av_get_pix_fmt_name);
LOAD_SYMBOL(avutil, av_get_sample_fmt_name);
LOAD_SYMBOL(avutil, av_hwdevice_ctx_create);
LOAD_SYMBOL(avutil, av_hwdevice_get_hwframe_constraints);
LOAD_SYMBOL(avutil, av_hwframe_constraints_free);
LOAD_SYMBOL(avutil, av_hwframe_ctx_alloc);
LOAD_SYMBOL(avutil, av_hwframe_ctx_init);
LOAD_SYMBOL(avutil, av_hwframe_get_buffer);
LOAD_SYMBOL(avutil, av_hwframe_transfer_data);
LOAD_SYMBOL(avutil, av_int_list_length_for_size);
#if LIBAVCODEC_VERSION_MAJOR >= 59
LOAD_SYMBOL(avutil, av_opt_child_class_iterate);
#else
LOAD_SYMBOL(avutil, av_opt_child_class_next);
#endif
LOAD_SYMBOL(avutil, av_opt_next);
LOAD_SYMBOL(avutil, av_opt_set_bin);
LOAD_SYMBOL(avutil, av_pix_fmt_desc_get);
LOAD_SYMBOL(avutil, av_pix_fmt_desc_next);
LOAD_SYMBOL(avutil, av_sample_fmt_is_planar);
LOAD_SYMBOL(avutil, av_samples_alloc_array_and_samples);
LOAD_SYMBOL(avutil, av_strdup);
if (any_failed) {
LOG_WARNING(Common, "Could not find all required functions in libavutil.");
avutil.reset();
return false;
}
LOG_INFO(Common, "Successfully loaded libavutil.");
return true;
}
static bool LoadAVCodec() {
if (avcodec) {
return true;
}
avcodec = std::make_unique<DynamicLibrary>("avcodec", LIBAVCODEC_VERSION_MAJOR);
if (!avcodec->IsLoaded()) {
LOG_WARNING(Common, "Could not dynamically load libavcodec: {}", avcodec->GetLoadError());
avcodec.reset();
return false;
}
auto any_failed = false;
LOAD_SYMBOL(avcodec, avcodec_version);
auto major_version = AV_VERSION_MAJOR(avcodec_version());
if (major_version != LIBAVCODEC_VERSION_MAJOR) {
LOG_WARNING(Common, "libavcodec version {} does not match supported version {}.",
major_version, LIBAVCODEC_VERSION_MAJOR);
avcodec.reset();
return false;
}
LOAD_SYMBOL(avcodec, av_codec_is_encoder);
LOAD_SYMBOL(avcodec, av_codec_iterate);
LOAD_SYMBOL(avcodec, av_init_packet);
LOAD_SYMBOL(avcodec, av_packet_alloc);
LOAD_SYMBOL(avcodec, av_packet_free);
LOAD_SYMBOL(avcodec, av_packet_rescale_ts);
LOAD_SYMBOL(avcodec, av_parser_close);
LOAD_SYMBOL(avcodec, av_parser_init);
LOAD_SYMBOL(avcodec, av_parser_parse2);
LOAD_SYMBOL(avcodec, avcodec_alloc_context3);
LOAD_SYMBOL(avcodec, avcodec_descriptor_next);
LOAD_SYMBOL(avcodec, avcodec_find_decoder);
LOAD_SYMBOL(avcodec, avcodec_find_encoder_by_name);
LOAD_SYMBOL(avcodec, avcodec_free_context);
LOAD_SYMBOL(avcodec, avcodec_get_class);
LOAD_SYMBOL(avcodec, avcodec_get_hw_config);
LOAD_SYMBOL(avcodec, avcodec_open2);
LOAD_SYMBOL(avcodec, avcodec_parameters_from_context);
LOAD_SYMBOL(avcodec, avcodec_receive_frame);
LOAD_SYMBOL(avcodec, avcodec_receive_packet);
LOAD_SYMBOL(avcodec, avcodec_send_frame);
LOAD_SYMBOL(avcodec, avcodec_send_packet);
if (any_failed) {
LOG_WARNING(Common, "Could not find all required functions in libavcodec.");
avcodec.reset();
return false;
}
LOG_INFO(Common, "Successfully loaded libavcodec.");
return true;
}
static bool LoadAVFilter() {
if (avfilter) {
return true;
}
avfilter = std::make_unique<DynamicLibrary>("avfilter", LIBAVFILTER_VERSION_MAJOR);
if (!avfilter->IsLoaded()) {
LOG_WARNING(Common, "Could not dynamically load libavfilter: {}", avfilter->GetLoadError());
avfilter.reset();
return false;
}
auto any_failed = false;
LOAD_SYMBOL(avfilter, avfilter_version);
auto major_version = AV_VERSION_MAJOR(avfilter_version());
if (major_version != LIBAVFILTER_VERSION_MAJOR) {
LOG_WARNING(Common, "libavfilter version {} does not match supported version {}.",
major_version, LIBAVFILTER_VERSION_MAJOR);
avfilter.reset();
return false;
}
LOAD_SYMBOL(avfilter, av_buffersink_get_frame);
LOAD_SYMBOL(avfilter, av_buffersrc_add_frame);
LOAD_SYMBOL(avfilter, avfilter_get_by_name);
LOAD_SYMBOL(avfilter, avfilter_graph_alloc);
LOAD_SYMBOL(avfilter, avfilter_graph_config);
LOAD_SYMBOL(avfilter, avfilter_graph_create_filter);
LOAD_SYMBOL(avfilter, avfilter_graph_free);
LOAD_SYMBOL(avfilter, avfilter_graph_parse_ptr);
LOAD_SYMBOL(avfilter, avfilter_inout_alloc);
LOAD_SYMBOL(avfilter, avfilter_inout_free);
if (any_failed) {
LOG_WARNING(Common, "Could not find all required functions in libavfilter.");
avfilter.reset();
return false;
}
LOG_INFO(Common, "Successfully loaded libavfilter.");
return true;
}
static bool LoadAVFormat() {
if (avformat) {
return true;
}
avformat = std::make_unique<DynamicLibrary>("avformat", LIBAVFORMAT_VERSION_MAJOR);
if (!avformat->IsLoaded()) {
LOG_WARNING(Common, "Could not dynamically load libavformat: {}", avformat->GetLoadError());
avformat.reset();
return false;
}
auto any_failed = false;
LOAD_SYMBOL(avformat, avformat_version);
auto major_version = AV_VERSION_MAJOR(avformat_version());
if (major_version != LIBAVFORMAT_VERSION_MAJOR) {
LOG_WARNING(Common, "libavformat version {} does not match supported version {}.",
major_version, LIBAVFORMAT_VERSION_MAJOR);
avformat.reset();
return false;
}
LOAD_SYMBOL(avformat, av_guess_format);
LOAD_SYMBOL(avformat, av_interleaved_write_frame);
LOAD_SYMBOL(avformat, av_muxer_iterate);
LOAD_SYMBOL(avformat, av_write_trailer);
LOAD_SYMBOL(avformat, avformat_alloc_output_context2);
LOAD_SYMBOL(avformat, avformat_free_context);
LOAD_SYMBOL(avformat, avformat_get_class);
LOAD_SYMBOL(avformat, avformat_network_init);
LOAD_SYMBOL(avformat, avformat_new_stream);
LOAD_SYMBOL(avformat, avformat_query_codec);
LOAD_SYMBOL(avformat, avformat_write_header);
LOAD_SYMBOL(avformat, avio_closep);
LOAD_SYMBOL(avformat, avio_open);
if (any_failed) {
LOG_WARNING(Common, "Could not find all required functions in libavformat.");
avformat.reset();
return false;
}
LOG_INFO(Common, "Successfully loaded libavformat.");
return true;
}
static bool LoadSWResample() {
if (swresample) {
return true;
}
swresample = std::make_unique<DynamicLibrary>("swresample", LIBSWRESAMPLE_VERSION_MAJOR);
if (!swresample->IsLoaded()) {
LOG_WARNING(Common, "Could not dynamically load libswresample: {}",
swresample->GetLoadError());
swresample.reset();
return false;
}
auto any_failed = false;
LOAD_SYMBOL(swresample, swresample_version);
auto major_version = AV_VERSION_MAJOR(swresample_version());
if (major_version != LIBSWRESAMPLE_VERSION_MAJOR) {
LOG_WARNING(Common, "libswresample version {} does not match supported version {}.",
major_version, LIBSWRESAMPLE_VERSION_MAJOR);
swresample.reset();
return false;
}
#if LIBSWRESAMPLE_VERSION_INT >= AV_VERSION_INT(4, 5, 100)
LOAD_SYMBOL(swresample, swr_alloc_set_opts2);
#else
LOAD_SYMBOL(swresample, swr_alloc_set_opts);
#endif
LOAD_SYMBOL(swresample, swr_convert);
LOAD_SYMBOL(swresample, swr_free);
LOAD_SYMBOL(swresample, swr_init);
if (any_failed) {
LOG_WARNING(Common, "Could not find all required functions in libswresample.");
swresample.reset();
return false;
}
LOG_INFO(Common, "Successfully loaded libswresample.");
return true;
}
bool LoadFFmpeg() {
return LoadAVUtil() && LoadAVCodec() && LoadAVFilter() && LoadAVFormat() && LoadSWResample();
}
} // namespace DynamicLibrary::FFmpeg

View file

@ -0,0 +1,236 @@
// Copyright 2023 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavfilter/avfilter.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/ffversion.h>
#include <libavutil/opt.h>
#include <libavutil/pixdesc.h>
#include <libswresample/swresample.h>
}
#include "common/common_types.h"
#include "common/dynamic_library/dynamic_library.h"
namespace DynamicLibrary::FFmpeg {
// avutil
typedef AVBufferRef* (*av_buffer_ref_func)(const AVBufferRef*);
typedef void (*av_buffer_unref_func)(AVBufferRef**);
typedef AVRational (*av_d2q_func)(double d, int max);
typedef int (*av_dict_count_func)(const AVDictionary*);
typedef AVDictionaryEntry* (*av_dict_get_func)(const AVDictionary*, const char*,
const AVDictionaryEntry*, int);
typedef int (*av_dict_get_string_func)(const AVDictionary*, char**, const char, const char);
typedef int (*av_dict_set_func)(AVDictionary**, const char*, const char*, int);
typedef AVFrame* (*av_frame_alloc_func)();
typedef void (*av_frame_free_func)(AVFrame**);
typedef void (*av_frame_unref_func)(AVFrame*);
typedef void (*av_freep_func)(void*);
typedef int (*av_get_bytes_per_sample_func)(AVSampleFormat);
typedef AVPixelFormat (*av_get_pix_fmt_func)(const char*);
typedef const char* (*av_get_pix_fmt_name_func)(AVPixelFormat);
typedef const char* (*av_get_sample_fmt_name_func)(AVSampleFormat);
typedef int (*av_hwdevice_ctx_create_func)(AVBufferRef**, AVHWDeviceType, const char*,
AVDictionary*, int);
typedef AVHWFramesConstraints* (*av_hwdevice_get_hwframe_constraints_func)(AVBufferRef*,
const void*);
typedef void (*av_hwframe_constraints_free_func)(AVHWFramesConstraints**);
typedef AVBufferRef* (*av_hwframe_ctx_alloc_func)(AVBufferRef*);
typedef int (*av_hwframe_ctx_init_func)(AVBufferRef*);
typedef int (*av_hwframe_get_buffer_func)(AVBufferRef*, AVFrame*, int);
typedef int (*av_hwframe_transfer_data_func)(AVFrame*, const AVFrame*, int);
typedef unsigned (*av_int_list_length_for_size_func)(unsigned, const void*, uint64_t);
#if LIBAVCODEC_VERSION_MAJOR >= 59
typedef const AVClass* (*av_opt_child_class_iterate_func)(const AVClass*, void**);
#else
typedef const AVClass* (*av_opt_child_class_next_func)(const AVClass*, const AVClass*);
#endif
typedef const AVOption* (*av_opt_next_func)(const void*, const AVOption*);
typedef int (*av_opt_set_bin_func)(void*, const char*, const uint8_t*, int, int);
typedef const AVPixFmtDescriptor* (*av_pix_fmt_desc_get_func)(AVPixelFormat);
typedef const AVPixFmtDescriptor* (*av_pix_fmt_desc_next_func)(const AVPixFmtDescriptor*);
typedef int (*av_sample_fmt_is_planar_func)(AVSampleFormat);
typedef int (*av_samples_alloc_array_and_samples_func)(uint8_t***, int*, int, int, AVSampleFormat,
int);
typedef char* (*av_strdup_func)(const char*);
typedef unsigned (*avutil_version_func)();
extern av_buffer_ref_func av_buffer_ref;
extern av_buffer_unref_func av_buffer_unref;
extern av_d2q_func av_d2q;
extern av_dict_count_func av_dict_count;
extern av_dict_get_func av_dict_get;
extern av_dict_get_string_func av_dict_get_string;
extern av_dict_set_func av_dict_set;
extern av_frame_alloc_func av_frame_alloc;
extern av_frame_free_func av_frame_free;
extern av_frame_unref_func av_frame_unref;
extern av_freep_func av_freep;
extern av_get_bytes_per_sample_func av_get_bytes_per_sample;
extern av_get_pix_fmt_func av_get_pix_fmt;
extern av_get_pix_fmt_name_func av_get_pix_fmt_name;
extern av_get_sample_fmt_name_func av_get_sample_fmt_name;
extern av_hwdevice_ctx_create_func av_hwdevice_ctx_create;
extern av_hwdevice_get_hwframe_constraints_func av_hwdevice_get_hwframe_constraints;
extern av_hwframe_constraints_free_func av_hwframe_constraints_free;
extern av_hwframe_ctx_alloc_func av_hwframe_ctx_alloc;
extern av_hwframe_ctx_init_func av_hwframe_ctx_init;
extern av_hwframe_get_buffer_func av_hwframe_get_buffer;
extern av_hwframe_transfer_data_func av_hwframe_transfer_data;
extern av_int_list_length_for_size_func av_int_list_length_for_size;
#if LIBAVCODEC_VERSION_MAJOR >= 59
extern av_opt_child_class_iterate_func av_opt_child_class_iterate;
#else
extern av_opt_child_class_next_func av_opt_child_class_next;
#endif
extern av_opt_next_func av_opt_next;
extern av_opt_set_bin_func av_opt_set_bin;
extern av_pix_fmt_desc_get_func av_pix_fmt_desc_get;
extern av_pix_fmt_desc_next_func av_pix_fmt_desc_next;
extern av_sample_fmt_is_planar_func av_sample_fmt_is_planar;
extern av_samples_alloc_array_and_samples_func av_samples_alloc_array_and_samples;
extern av_strdup_func av_strdup;
extern avutil_version_func avutil_version;
// avcodec
typedef int (*av_codec_is_encoder_func)(const AVCodec*);
typedef const AVCodec* (*av_codec_iterate_func)(void**);
typedef void (*av_init_packet_func)(AVPacket*);
typedef AVPacket* (*av_packet_alloc_func)();
typedef void (*av_packet_free_func)(AVPacket**);
typedef void (*av_packet_rescale_ts_func)(AVPacket*, AVRational, AVRational);
typedef void (*av_parser_close_func)(AVCodecParserContext*);
typedef AVCodecParserContext* (*av_parser_init_func)(int);
typedef int (*av_parser_parse2_func)(AVCodecParserContext*, AVCodecContext*, uint8_t**, int*,
const uint8_t*, int, int64_t, int64_t, int64_t);
typedef AVCodecContext* (*avcodec_alloc_context3_func)(const AVCodec*);
typedef const AVCodecDescriptor* (*avcodec_descriptor_next_func)(const AVCodecDescriptor*);
typedef AVCodec* (*avcodec_find_decoder_func)(AVCodecID);
typedef const AVCodec* (*avcodec_find_encoder_by_name_func)(const char*);
typedef void (*avcodec_free_context_func)(AVCodecContext**);
typedef const AVClass* (*avcodec_get_class_func)();
typedef const AVCodecHWConfig* (*avcodec_get_hw_config_func)(const AVCodec*, int);
typedef int (*avcodec_open2_func)(AVCodecContext*, const AVCodec*, AVDictionary**);
typedef int (*avcodec_parameters_from_context_func)(AVCodecParameters* par, const AVCodecContext*);
typedef int (*avcodec_receive_frame_func)(AVCodecContext*, AVFrame*);
typedef int (*avcodec_receive_packet_func)(AVCodecContext*, AVPacket*);
typedef int (*avcodec_send_frame_func)(AVCodecContext*, const AVFrame*);
typedef int (*avcodec_send_packet_func)(AVCodecContext*, const AVPacket*);
typedef unsigned (*avcodec_version_func)();
extern av_codec_is_encoder_func av_codec_is_encoder;
extern av_codec_iterate_func av_codec_iterate;
extern av_init_packet_func av_init_packet;
extern av_packet_alloc_func av_packet_alloc;
extern av_packet_free_func av_packet_free;
extern av_packet_rescale_ts_func av_packet_rescale_ts;
extern av_parser_close_func av_parser_close;
extern av_parser_init_func av_parser_init;
extern av_parser_parse2_func av_parser_parse2;
extern avcodec_alloc_context3_func avcodec_alloc_context3;
extern avcodec_descriptor_next_func avcodec_descriptor_next;
extern avcodec_find_decoder_func avcodec_find_decoder;
extern avcodec_find_encoder_by_name_func avcodec_find_encoder_by_name;
extern avcodec_free_context_func avcodec_free_context;
extern avcodec_get_class_func avcodec_get_class;
extern avcodec_get_hw_config_func avcodec_get_hw_config;
extern avcodec_open2_func avcodec_open2;
extern avcodec_parameters_from_context_func avcodec_parameters_from_context;
extern avcodec_receive_frame_func avcodec_receive_frame;
extern avcodec_receive_packet_func avcodec_receive_packet;
extern avcodec_send_frame_func avcodec_send_frame;
extern avcodec_send_packet_func avcodec_send_packet;
extern avcodec_version_func avcodec_version;
// avfilter
typedef int (*av_buffersink_get_frame_func)(AVFilterContext*, AVFrame*);
typedef int (*av_buffersrc_add_frame_func)(AVFilterContext*, AVFrame*);
typedef const AVFilter* (*avfilter_get_by_name_func)(const char*);
typedef AVFilterGraph* (*avfilter_graph_alloc_func)();
typedef int (*avfilter_graph_config_func)(AVFilterGraph*, void*);
typedef int (*avfilter_graph_create_filter_func)(AVFilterContext**, const AVFilter*, const char*,
const char*, void*, AVFilterGraph*);
typedef void (*avfilter_graph_free_func)(AVFilterGraph** graph);
typedef int (*avfilter_graph_parse_ptr_func)(AVFilterGraph*, const char*, AVFilterInOut**,
AVFilterInOut**, void*);
typedef AVFilterInOut* (*avfilter_inout_alloc_func)();
typedef void (*avfilter_inout_free_func)(AVFilterInOut**);
typedef unsigned (*avfilter_version_func)();
extern av_buffersink_get_frame_func av_buffersink_get_frame;
extern av_buffersrc_add_frame_func av_buffersrc_add_frame;
extern avfilter_get_by_name_func avfilter_get_by_name;
extern avfilter_graph_alloc_func avfilter_graph_alloc;
extern avfilter_graph_config_func avfilter_graph_config;
extern avfilter_graph_create_filter_func avfilter_graph_create_filter;
extern avfilter_graph_free_func avfilter_graph_free;
extern avfilter_graph_parse_ptr_func avfilter_graph_parse_ptr;
extern avfilter_inout_alloc_func avfilter_inout_alloc;
extern avfilter_inout_free_func avfilter_inout_free;
extern avfilter_version_func avfilter_version;
// avformat
typedef const AVOutputFormat* (*av_guess_format_func)(const char*, const char*, const char*);
typedef int (*av_interleaved_write_frame_func)(AVFormatContext*, AVPacket*);
typedef const AVOutputFormat* (*av_muxer_iterate_func)(void**);
typedef int (*av_write_trailer_func)(AVFormatContext*);
typedef int (*avformat_alloc_output_context2_func)(AVFormatContext**, const AVOutputFormat*,
const char*, const char*);
typedef void (*avformat_free_context_func)(AVFormatContext*);
typedef const AVClass* (*avformat_get_class_func)();
typedef int (*avformat_network_init_func)();
typedef AVStream* (*avformat_new_stream_func)(AVFormatContext*, const AVCodec*);
typedef int (*avformat_query_codec_func)(const AVOutputFormat*, AVCodecID, int);
typedef int (*avformat_write_header_func)(AVFormatContext*, AVDictionary**);
typedef unsigned (*avformat_version_func)();
typedef int (*avio_closep_func)(AVIOContext**);
typedef int (*avio_open_func)(AVIOContext**, const char*, int);
extern av_guess_format_func av_guess_format;
extern av_interleaved_write_frame_func av_interleaved_write_frame;
extern av_muxer_iterate_func av_muxer_iterate;
extern av_write_trailer_func av_write_trailer;
extern avformat_alloc_output_context2_func avformat_alloc_output_context2;
extern avformat_free_context_func avformat_free_context;
extern avformat_get_class_func avformat_get_class;
extern avformat_network_init_func avformat_network_init;
extern avformat_new_stream_func avformat_new_stream;
extern avformat_query_codec_func avformat_query_codec;
extern avformat_write_header_func avformat_write_header;
extern avformat_version_func avformat_version;
extern avio_closep_func avio_closep;
extern avio_open_func avio_open;
// swresample
#if LIBSWRESAMPLE_VERSION_INT >= AV_VERSION_INT(4, 5, 100)
typedef SwrContext* (*swr_alloc_set_opts2_func)(SwrContext**, AVChannelLayout*, AVSampleFormat, int,
AVChannelLayout*, AVSampleFormat, int, int, void*);
#else
typedef SwrContext* (*swr_alloc_set_opts_func)(SwrContext*, int64_t, AVSampleFormat, int, int64_t,
AVSampleFormat, int, int, void*);
#endif
typedef int (*swr_convert_func)(SwrContext*, uint8_t**, int, const uint8_t**, int);
typedef void (*swr_free_func)(SwrContext**);
typedef int (*swr_init_func)(SwrContext*);
typedef unsigned (*swresample_version_func)();
#if LIBSWRESAMPLE_VERSION_INT >= AV_VERSION_INT(4, 5, 100)
extern swr_alloc_set_opts2_func swr_alloc_set_opts2;
#else
extern swr_alloc_set_opts_func swr_alloc_set_opts;
#endif
extern swr_convert_func swr_convert;
extern swr_free_func swr_free;
extern swr_init_func swr_init;
extern swresample_version_func swresample_version;
bool LoadFFmpeg();
} // namespace DynamicLibrary::FFmpeg