mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	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
				
			
		
							
								
								
									
										87
									
								
								src/common/dynamic_library/dynamic_library.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								src/common/dynamic_library/dynamic_library.cpp
									
										
									
									
									
										Normal 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
 | ||||
							
								
								
									
										39
									
								
								src/common/dynamic_library/dynamic_library.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/common/dynamic_library/dynamic_library.h
									
										
									
									
									
										Normal 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
 | ||||
							
								
								
									
										54
									
								
								src/common/dynamic_library/fdk-aac.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/common/dynamic_library/fdk-aac.cpp
									
										
									
									
									
										Normal 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
 | ||||
							
								
								
									
										37
									
								
								src/common/dynamic_library/fdk-aac.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/common/dynamic_library/fdk-aac.h
									
										
									
									
									
										Normal 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
 | ||||
							
								
								
									
										390
									
								
								src/common/dynamic_library/ffmpeg.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										390
									
								
								src/common/dynamic_library/ffmpeg.cpp
									
										
									
									
									
										Normal 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
 | ||||
							
								
								
									
										236
									
								
								src/common/dynamic_library/ffmpeg.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										236
									
								
								src/common/dynamic_library/ffmpeg.h
									
										
									
									
									
										Normal 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
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue