Dynamically load FFmpeg and libfdk-aac if available. (#6570)
parent
d807cdfe62
commit
38435e9b3e
@ -1,7 +1,7 @@
|
||||
#!/bin/bash -ex
|
||||
|
||||
mkdir build && cd build
|
||||
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DENABLE_QT_TRANSLATION=ON -DCITRA_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON -DENABLE_FFMPEG_VIDEO_DUMPER=ON
|
||||
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DENABLE_QT_TRANSLATION=ON -DCITRA_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON
|
||||
ninja
|
||||
|
||||
ctest -VV -C Release
|
||||
|
@ -1,13 +0,0 @@
|
||||
function(copy_citra_FFmpeg_deps target_dir)
|
||||
include(WindowsCopyFiles)
|
||||
set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
|
||||
windows_copy_files(${target_dir} ${FFMPEG_DIR}/bin ${DLL_DEST}
|
||||
avcodec*.dll
|
||||
avfilter*.dll
|
||||
avformat*.dll
|
||||
avutil*.dll
|
||||
postproc*.dll
|
||||
swresample*.dll
|
||||
swscale*.dll
|
||||
)
|
||||
endfunction(copy_citra_FFmpeg_deps)
|
@ -1,192 +0,0 @@
|
||||
# FindFFmpeg
|
||||
# ----------
|
||||
#
|
||||
# Find the native FFmpeg includes and libraries
|
||||
#
|
||||
# This module defines the following variables:
|
||||
#
|
||||
# FFmpeg_INCLUDE_<component>: where to find <component>.h
|
||||
# FFmpeg_LIBRARY_<component>: where to find the <component> library
|
||||
# FFmpeg_INCLUDES: aggregate all the include paths
|
||||
# FFmpeg_LIBRARIES: aggregate all the paths to the libraries
|
||||
# FFmpeg_FOUND: True if all components have been found
|
||||
#
|
||||
# This module defines the following targets, which are prefered over variables:
|
||||
#
|
||||
# FFmpeg::<component>: Target to use <component> directly, with include path,
|
||||
# library and dependencies set up. If you are using a static build, you are
|
||||
# responsible for adding any external dependencies (such as zlib, bzlib...).
|
||||
#
|
||||
# <component> can be one of:
|
||||
# avcodec
|
||||
# avdevice
|
||||
# avfilter
|
||||
# avformat
|
||||
# postproc
|
||||
# swresample
|
||||
# swscale
|
||||
#
|
||||
|
||||
set(_FFmpeg_ALL_COMPONENTS
|
||||
avcodec
|
||||
avdevice
|
||||
avfilter
|
||||
avformat
|
||||
avutil
|
||||
postproc
|
||||
swresample
|
||||
swscale
|
||||
)
|
||||
|
||||
set(_FFmpeg_DEPS_avcodec avutil)
|
||||
set(_FFmpeg_DEPS_avdevice avcodec avformat avutil)
|
||||
set(_FFmpeg_DEPS_avfilter avutil)
|
||||
set(_FFmpeg_DEPS_avformat avcodec avutil)
|
||||
set(_FFmpeg_DEPS_postproc avutil)
|
||||
set(_FFmpeg_DEPS_swresample avutil)
|
||||
set(_FFmpeg_DEPS_swscale avutil)
|
||||
|
||||
function(find_ffmpeg LIBNAME)
|
||||
if(DEFINED ENV{FFMPEG_DIR})
|
||||
set(FFMPEG_DIR $ENV{FFMPEG_DIR})
|
||||
endif()
|
||||
|
||||
if(FFMPEG_DIR)
|
||||
list(APPEND INCLUDE_PATHS
|
||||
${FFMPEG_DIR}
|
||||
${FFMPEG_DIR}/ffmpeg
|
||||
${FFMPEG_DIR}/lib${LIBNAME}
|
||||
${FFMPEG_DIR}/include/lib${LIBNAME}
|
||||
${FFMPEG_DIR}/include/ffmpeg
|
||||
${FFMPEG_DIR}/include
|
||||
NO_DEFAULT_PATH
|
||||
NO_CMAKE_FIND_ROOT_PATH
|
||||
)
|
||||
list(APPEND LIB_PATHS
|
||||
${FFMPEG_DIR}
|
||||
${FFMPEG_DIR}/lib
|
||||
${FFMPEG_DIR}/lib${LIBNAME}
|
||||
NO_DEFAULT_PATH
|
||||
NO_CMAKE_FIND_ROOT_PATH
|
||||
)
|
||||
else()
|
||||
list(APPEND INCLUDE_PATHS
|
||||
/usr/local/include/ffmpeg
|
||||
/usr/local/include/lib${LIBNAME}
|
||||
/usr/include/ffmpeg
|
||||
/usr/include/lib${LIBNAME}
|
||||
/usr/include/ffmpeg/lib${LIBNAME}
|
||||
)
|
||||
|
||||
list(APPEND LIB_PATHS
|
||||
/usr/local/lib
|
||||
/usr/lib
|
||||
)
|
||||
endif()
|
||||
|
||||
find_path(FFmpeg_INCLUDE_${LIBNAME} lib${LIBNAME}/${LIBNAME}.h
|
||||
HINTS ${INCLUDE_PATHS}
|
||||
)
|
||||
|
||||
find_library(FFmpeg_LIBRARY_${LIBNAME} ${LIBNAME}
|
||||
HINTS ${LIB_PATHS}
|
||||
)
|
||||
|
||||
if(NOT FFMPEG_DIR AND (NOT FFmpeg_LIBRARY_${LIBNAME} OR NOT FFmpeg_INCLUDE_${LIBNAME}))
|
||||
# Didn't find it in the usual paths, try pkg-config
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_check_modules(FFmpeg_PKGCONFIG_${LIBNAME} QUIET lib${LIBNAME})
|
||||
|
||||
find_path(FFmpeg_INCLUDE_${LIBNAME} lib${LIBNAME}/${LIBNAME}.h
|
||||
${FFmpeg_PKGCONFIG_${LIBNAME}_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
find_library(FFmpeg_LIBRARY_${LIBNAME} ${LIBNAME}
|
||||
${FFmpeg_PKGCONFIG_${LIBNAME}_LIBRARY_DIRS}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(FFmpeg_INCLUDE_${LIBNAME} AND FFmpeg_LIBRARY_${LIBNAME})
|
||||
set(FFmpeg_INCLUDE_${LIBNAME} "${FFmpeg_INCLUDE_${LIBNAME}}" PARENT_SCOPE)
|
||||
set(FFmpeg_LIBRARY_${LIBNAME} "${FFmpeg_LIBRARY_${LIBNAME}}" PARENT_SCOPE)
|
||||
|
||||
# Extract FFmpeg version from version.h
|
||||
foreach(v MAJOR MINOR MICRO)
|
||||
set(FFmpeg_${LIBNAME}_VERSION_${v} 0)
|
||||
endforeach()
|
||||
string(TOUPPER ${LIBNAME} LIBNAME_UPPER)
|
||||
file(STRINGS "${FFmpeg_INCLUDE_${LIBNAME}}/lib${LIBNAME}/version.h" _FFmpeg_VERSION_H_CONTENTS REGEX "#define LIB${LIBNAME_UPPER}_VERSION_(MAJOR|MINOR|MICRO) ")
|
||||
if (EXISTS "${FFmpeg_INCLUDE_${LIBNAME}}/lib${LIBNAME}/version_major.h")
|
||||
file(STRINGS "${FFmpeg_INCLUDE_${LIBNAME}}/lib${LIBNAME}/version_major.h" _FFmpeg_MAJOR_VERSION_H_CONTENTS REGEX "#define LIB${LIBNAME_UPPER}_VERSION_MAJOR ")
|
||||
string(APPEND _FFmpeg_VERSION_H_CONTENTS "\n" ${_FFmpeg_MAJOR_VERSION_H_CONTENTS})
|
||||
endif()
|
||||
set(_FFmpeg_VERSION_REGEX "([0-9]+)")
|
||||
foreach(v MAJOR MINOR MICRO)
|
||||
if("${_FFmpeg_VERSION_H_CONTENTS}" MATCHES "#define LIB${LIBNAME_UPPER}_VERSION_${v}[\\t ]+${_FFmpeg_VERSION_REGEX}")
|
||||
set(FFmpeg_${LIBNAME}_VERSION_${v} "${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
endforeach()
|
||||
set(FFmpeg_${LIBNAME}_VERSION "${FFmpeg_${LIBNAME}_VERSION_MAJOR}.${FFmpeg_${LIBNAME}_VERSION_MINOR}.${FFmpeg_${LIBNAME}_VERSION_MICRO}")
|
||||
set(FFmpeg_${c}_VERSION "${FFmpeg_${LIBNAME}_VERSION}" PARENT_SCOPE)
|
||||
unset(_FFmpeg_VERSION_REGEX)
|
||||
unset(_FFmpeg_VERSION_H_CONTENTS)
|
||||
|
||||
set(FFmpeg_${c}_FOUND TRUE PARENT_SCOPE)
|
||||
if(NOT FFmpeg_FIND_QUIETLY)
|
||||
message("-- Found ${LIBNAME}: ${FFmpeg_INCLUDE_${LIBNAME}} ${FFmpeg_LIBRARY_${LIBNAME}} (version: ${FFmpeg_${LIBNAME}_VERSION})")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
foreach(c ${_FFmpeg_ALL_COMPONENTS})
|
||||
find_ffmpeg(${c})
|
||||
endforeach()
|
||||
|
||||
foreach(c ${_FFmpeg_ALL_COMPONENTS})
|
||||
if(FFmpeg_${c}_FOUND)
|
||||
list(APPEND FFmpeg_INCLUDES ${FFmpeg_INCLUDE_${c}})
|
||||
list(APPEND FFmpeg_LIBRARIES ${FFmpeg_LIBRARY_${c}})
|
||||
|
||||
add_library(FFmpeg::${c} IMPORTED UNKNOWN)
|
||||
set_target_properties(FFmpeg::${c} PROPERTIES
|
||||
IMPORTED_LOCATION ${FFmpeg_LIBRARY_${c}}
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${FFmpeg_INCLUDE_${c}}
|
||||
)
|
||||
if(APPLE)
|
||||
set_target_properties(FFmpeg::${c} PROPERTIES
|
||||
MACOSX_RPATH 1
|
||||
)
|
||||
endif()
|
||||
if(_FFmpeg_DEPS_${c})
|
||||
set(deps)
|
||||
foreach(dep ${_FFmpeg_DEPS_${c}})
|
||||
list(APPEND deps FFmpeg::${dep})
|
||||
endforeach()
|
||||
|
||||
set_target_properties(FFmpeg::${c} PROPERTIES
|
||||
INTERFACE_LINK_LIBRARIES "${deps}"
|
||||
)
|
||||
unset(deps)
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(FFmpeg_INCLUDES)
|
||||
list(REMOVE_DUPLICATES FFmpeg_INCLUDES)
|
||||
endif()
|
||||
|
||||
foreach(c ${FFmpeg_FIND_COMPONENTS})
|
||||
list(APPEND _FFmpeg_REQUIRED_VARS FFmpeg_INCLUDE_${c} FFmpeg_LIBRARY_${c})
|
||||
endforeach()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(FFmpeg
|
||||
REQUIRED_VARS ${_FFmpeg_REQUIRED_VARS}
|
||||
HANDLE_COMPONENTS
|
||||
)
|
||||
|
||||
foreach(c ${_FFmpeg_ALL_COMPONENTS})
|
||||
unset(_FFmpeg_DEPS_${c})
|
||||
endforeach()
|
||||
unset(_FFmpeg_ALL_COMPONENTS)
|
||||
unset(_FFmpeg_REQUIRED_VARS)
|
@ -0,0 +1 @@
|
||||
Subproject commit 071bc4282ca29ec255ab2dae32c978481ca5dfea
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
Loading…
Reference in New Issue