diff --git a/YUViewLib/src/ffmpeg/FFmpegLibraryFunctions.cpp b/YUViewLib/src/ffmpeg/FFmpegLibraryFunctions.cpp index d4ffa014c..78def6496 100644 --- a/YUViewLib/src/ffmpeg/FFmpegLibraryFunctions.cpp +++ b/YUViewLib/src/ffmpeg/FFmpegLibraryFunctions.cpp @@ -36,12 +36,29 @@ namespace FFmpeg { +static QMutex mutex; +static bool isLibLoaded; +static QString avformatLibPath; +static QString avcodecLibPath; +static QString avutilLibPath; +static QString swresampleLibPath; +static QString libDirectoryPath; +static QLibrary libAvutil; +static QLibrary libSwresample; +static QLibrary libAvcodec; +static QLibrary libAvformat; + +FFmpegLibraryFunctions::AvFormatFunctions FFmpegLibraryFunctions::avformat{}; +FFmpegLibraryFunctions::AvCodecFunctions FFmpegLibraryFunctions::avcodec{}; +FFmpegLibraryFunctions::AvUtilFunctions FFmpegLibraryFunctions::avutil{}; +FFmpegLibraryFunctions::SwResampleFunction FFmpegLibraryFunctions::swresample{}; + namespace { template bool resolveFunction(QLibrary & lib, - std::function &function, + T &function, const char * symbolName, QStringList * logList) { @@ -53,7 +70,7 @@ bool resolveFunction(QLibrary & lib, return false; } - function = reinterpret_cast(ptr); + function = reinterpret_cast(ptr); return true; } @@ -179,13 +196,15 @@ bool bindLibraryFunctions(QLibrary & lib, FFmpegLibraryFunctions::~FFmpegLibraryFunctions() { - this->unloadAllLibraries(); } bool FFmpegLibraryFunctions::loadFFmpegLibraryInPath(QString path, LibraryVersion &libraryVersion) { // We will load the following libraries (in this order): // avutil, swresample, avcodec, avformat. + QMutexLocker locker(&mutex); + if (isLibLoaded && libDirectoryPath == path) + return true; if (!path.isEmpty()) { @@ -210,7 +229,7 @@ bool FFmpegLibraryFunctions::loadFFmpegLibraryInPath(QString path, LibraryVersio bool success = false; for (unsigned i = 0; i < nrNames; i++) { - this->unloadAllLibraries(); + this->unloadAllLibrariesLocked(); // This is how we the library name is constructed per platform QString constructLibName; @@ -224,21 +243,22 @@ bool FFmpegLibraryFunctions::loadFFmpegLibraryInPath(QString path, LibraryVersio constructLibName = "lib%1.%2.dylib"; auto loadLibrary = - [this, &constructLibName, &path](QLibrary &lib, QString libName, unsigned version) { + [this, &constructLibName, &path](QLibrary &lib, QString libName, unsigned version, QString &output) { auto filename = constructLibName.arg(libName).arg(version); lib.setFileName(path + filename); auto success = lib.load(); this->log("Loading library " + filename + (success ? " succeded" : " failed")); + output = path + filename; return success; }; - if (!loadLibrary(this->libAvutil, "avutil", libraryVersion.avutil.major)) + if (!loadLibrary(libAvutil, "avutil", libraryVersion.avutil.major, avutilLibPath)) continue; - if (!loadLibrary(this->libSwresample, "swresample", libraryVersion.swresample.major)) + if (!loadLibrary(libSwresample, "swresample", libraryVersion.swresample.major, swresampleLibPath)) continue; - if (!loadLibrary(this->libAvcodec, "avcodec", libraryVersion.avcodec.major)) + if (!loadLibrary(libAvcodec, "avcodec", libraryVersion.avcodec.major, avcodecLibPath)) continue; - if (!loadLibrary(this->libAvformat, "avformat", libraryVersion.avformat.major)) + if (!loadLibrary(libAvformat, "avformat", libraryVersion.avformat.major, avformatLibPath)) continue; success = true; @@ -247,16 +267,22 @@ bool FFmpegLibraryFunctions::loadFFmpegLibraryInPath(QString path, LibraryVersio if (!success) { - this->unloadAllLibraries(); + this->unloadAllLibrariesLocked(); return false; } - success = (bindLibraryFunctions(this->libAvformat, this->avformat, this->logList) && - bindLibraryFunctions(this->libAvcodec, this->avcodec, this->logList) && - bindLibraryFunctions(this->libAvutil, this->avutil, this->logList) && - bindLibraryFunctions(this->libSwresample, this->swresample, this->logList)); + success = (bindLibraryFunctions(libAvformat, avformat, this->logList) && + bindLibraryFunctions(libAvcodec, avcodec, this->logList) && + bindLibraryFunctions(libAvutil, avutil, this->logList) && + bindLibraryFunctions(libSwresample, swresample, this->logList)); this->log(QString("Binding functions ") + (success ? "successfull" : "failed")); + if (!success) + { + this->unloadAllLibrariesLocked(); + return false; + } + isLibLoaded = true; return success; } @@ -265,7 +291,18 @@ bool FFmpegLibraryFunctions::loadFFMpegLibrarySpecific(QString avFormatLib, QString avUtilLib, QString swResampleLib) { - this->unloadAllLibraries(); + QMutexLocker locker(&mutex); + this->log("loadFFMpegLibrarySpecific()..."); + if (isLibLoaded + && avFormatLib == avformatLibPath + && avCodecLib == avcodecLibPath + && avUtilLib == avutilLibPath + && swResampleLib == swresampleLibPath) { + return true; + } + if (isLibLoaded) { + this->unloadAllLibrariesLocked(); + } auto loadLibrary = [this](QLibrary &lib, QString libPath) { lib.setFileName(libPath); @@ -274,23 +311,31 @@ bool FFmpegLibraryFunctions::loadFFMpegLibrarySpecific(QString avFormatLib, return success; }; - auto success = (loadLibrary(this->libAvutil, avUtilLib) && // - loadLibrary(this->libSwresample, swResampleLib) && // - loadLibrary(this->libAvcodec, avCodecLib) && // - loadLibrary(this->libAvformat, avFormatLib)); + auto success = (loadLibrary(libAvutil, avUtilLib) && // + loadLibrary(libSwresample, swResampleLib) && // + loadLibrary(libAvcodec, avCodecLib) && // + loadLibrary(libAvformat, avFormatLib)); - if (!success) - { - this->unloadAllLibraries(); + if (!success) { + this->unloadAllLibrariesLocked(); return false; } - success = (bindLibraryFunctions(this->libAvformat, this->avformat, this->logList) && - bindLibraryFunctions(this->libAvcodec, this->avcodec, this->logList) && - bindLibraryFunctions(this->libAvutil, this->avutil, this->logList) && - bindLibraryFunctions(this->libSwresample, this->swresample, this->logList)); + success = (bindLibraryFunctions(libAvformat, avformat, this->logList) && + bindLibraryFunctions(libAvcodec, avcodec, this->logList) && + bindLibraryFunctions(libAvutil, avutil, this->logList) && + bindLibraryFunctions(libSwresample, swresample, this->logList)); this->log(QString("Binding functions ") + (success ? "successfull" : "failed")); + if (!success) { + this->unloadAllLibrariesLocked(); + return false; + } + avformatLibPath = avFormatLib; + avcodecLibPath = avCodecLib; + avutilLibPath = avUtilLib; + swresampleLibPath = swResampleLib; + isLibLoaded = true; return success; } @@ -311,13 +356,18 @@ void FFmpegLibraryFunctions::addLibNamesToList(QString libName, } } -void FFmpegLibraryFunctions::unloadAllLibraries() +void FFmpegLibraryFunctions::unloadAllLibrariesLocked() { this->log("Unloading all loaded libraries"); - this->libAvutil.unload(); - this->libSwresample.unload(); - this->libAvcodec.unload(); - this->libAvformat.unload(); + libAvutil.unload(); + libSwresample.unload(); + libAvcodec.unload(); + libAvformat.unload(); + avcodec = {}; + avformat = {}; + avutil = {}; + swresample = {}; + isLibLoaded = false; } QStringList FFmpegLibraryFunctions::getLibPaths() const @@ -338,10 +388,10 @@ QStringList FFmpegLibraryFunctions::getLibPaths() const } }; - addName("AVCodec", this->libAvcodec); - addName("AVFormat", this->libAvformat); - addName("AVUtil", this->libAvutil); - addName("SwResample", this->libSwresample); + addName("AVCodec", libAvcodec); + addName("AVFormat", libAvformat); + addName("AVUtil", libAvutil); + addName("SwResample", libSwresample); return libPaths; } diff --git a/YUViewLib/src/ffmpeg/FFmpegLibraryFunctions.h b/YUViewLib/src/ffmpeg/FFmpegLibraryFunctions.h index 4f0487a62..44bec220f 100644 --- a/YUViewLib/src/ffmpeg/FFmpegLibraryFunctions.h +++ b/YUViewLib/src/ffmpeg/FFmpegLibraryFunctions.h @@ -34,6 +34,8 @@ #include "FFMpegLibrariesTypes.h" #include +#include +#include #include namespace FFmpeg @@ -57,86 +59,81 @@ class FFmpegLibraryFunctions struct AvFormatFunctions { - std::function av_register_all; - std::function - avformat_open_input; - std::function avformat_close_input; - std::function avformat_find_stream_info; - std::function av_read_frame; - std::function - av_seek_frame; - std::function avformat_version; + void (*av_register_all)(); + int(*avformat_open_input)( + AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options); + ; + void (*avformat_close_input)(AVFormatContext **s) ; + int (*avformat_find_stream_info)(AVFormatContext *ic, AVDictionary **options) ; + int (*av_read_frame)(AVFormatContext *s, AVPacket *pkt) ; + int (*av_seek_frame)(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) + ; + unsigned(*avformat_version)() ; }; - AvFormatFunctions avformat{}; + static AvFormatFunctions avformat; struct AvCodecFunctions { - std::function avcodec_find_decoder; - std::function avcodec_alloc_context3; - std::function - avcodec_open2; - std::function avcodec_free_context; - std::function av_packet_alloc; - std::function av_packet_free; - std::function av_init_packet; - std::function av_packet_unref; - std::function avcodec_flush_buffers; - std::function avcodec_version; - std::function avcodec_get_name; - std::function avcodec_parameters_alloc; + AVCodec *(*avcodec_find_decoder)(AVCodecID id) ; + AVCodecContext *(*avcodec_alloc_context3)(const AVCodec *codec) ; + int (*avcodec_open2)(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options) ; + void (*avcodec_free_context)(AVCodecContext **avctx) ; + AVPacket *(*av_packet_alloc)() ; + void (*av_packet_free)(AVPacket **pkt) ; + void (*av_init_packet)(AVPacket *pkt) ; + void (*av_packet_unref)(AVPacket *pkt) ; + void (*avcodec_flush_buffers)(AVCodecContext *avctx) ; + unsigned(*avcodec_version)() ; + const char *(*avcodec_get_name)(AVCodecID id) ; + AVCodecParameters *(*avcodec_parameters_alloc)() ; // The following functions are part of the new API. // We will check if it is available. If not, we will use the old decoding API. bool newParametersAPIAvailable{}; - std::function avcodec_send_packet; - std::function avcodec_receive_frame; - std::function - avcodec_parameters_to_context; - std::function avcodec_decode_video2; + int (*avcodec_send_packet)(AVCodecContext *avctx, const AVPacket *avpkt) ; + int (*avcodec_receive_frame)(AVCodecContext *avctx, AVFrame *frame) ; + int (*avcodec_parameters_to_context)(AVCodecContext *codec, const AVCodecParameters *par) + ; + void (*avcodec_decode_video2)() ; }; - AvCodecFunctions avcodec{}; + static AvCodecFunctions avcodec; struct AvUtilFunctions { - std::function av_frame_alloc; - std::function av_frame_free; - std::function av_mallocz; - std::function avutil_version; - std::function - av_dict_set; - std::function - av_dict_get; - std::function - av_frame_get_side_data; - std::function av_frame_get_metadata; - std::function av_log_set_callback; - std::function av_log_set_level; - std::function av_pix_fmt_desc_get; - std::function av_pix_fmt_desc_next; - std::function av_pix_fmt_desc_get_id; + AVFrame *(*av_frame_alloc)() ; + void (*av_frame_free)(AVFrame **frame) ; + void (*av_mallocz)(size_t size) ; + unsigned(*avutil_version)() ; + int (*av_dict_set)(AVDictionary **pm, const char *key, const char *value, int flags) + ; + AVDictionaryEntry*(*av_dict_get)( + AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags) + ; + AVFrameSideData *(*av_frame_get_side_data)(const AVFrame *frame, AVFrameSideDataType type) + ; + AVDictionary *(*av_frame_get_metadata)(const AVFrame *frame) ; + void (*av_log_set_callback)(void (*callback)(void *, int, const char *, va_list)) ; + void (*av_log_set_level)(int level) ; + AVPixFmtDescriptor *(*av_pix_fmt_desc_get)(AVPixelFormat pix_fmt) ; + AVPixFmtDescriptor *(*av_pix_fmt_desc_next)(const AVPixFmtDescriptor *prev) ; + AVPixelFormat (*av_pix_fmt_desc_get_id)(const AVPixFmtDescriptor *desc) ; }; - AvUtilFunctions avutil{}; + static AvUtilFunctions avutil; struct SwResampleFunction { - std::function swresample_version; + unsigned(*swresample_version)() ; }; - SwResampleFunction swresample{}; + static SwResampleFunction swresample; void setLogList(QStringList *l) { logList = l; } private: void addLibNamesToList(QString libName, QStringList &l, const QLibrary &lib) const; - void unloadAllLibraries(); + void unloadAllLibrariesLocked(); QStringList *logList{}; void log(QString message); - QLibrary libAvutil; - QLibrary libSwresample; - QLibrary libAvcodec; - QLibrary libAvformat; }; } // namespace FFmpeg