Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 85 additions & 35 deletions YUViewLib/src/ffmpeg/FFmpegLibraryFunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename T>
bool resolveFunction(QLibrary & lib,
std::function<T> &function,
T &function,
const char * symbolName,
QStringList * logList)
{
Expand All @@ -53,7 +70,7 @@ bool resolveFunction(QLibrary & lib,
return false;
}

function = reinterpret_cast<T *>(ptr);
function = reinterpret_cast<T>(ptr);
return true;
}

Expand Down Expand Up @@ -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())
{
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
}

Expand All @@ -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);
Expand All @@ -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;
}

Expand All @@ -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
Expand All @@ -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;
}
Expand Down
107 changes: 52 additions & 55 deletions YUViewLib/src/ffmpeg/FFmpegLibraryFunctions.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@

#include "FFMpegLibrariesTypes.h"
#include <QLibrary>
#include <QMutex>
#include <QMutexLocker>
#include <common/Typedef.h>

namespace FFmpeg
Expand All @@ -57,86 +59,81 @@ class FFmpegLibraryFunctions

struct AvFormatFunctions
{
std::function<void()> av_register_all;
std::function<int(
AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options)>
avformat_open_input;
std::function<void(AVFormatContext **s)> avformat_close_input;
std::function<int(AVFormatContext *ic, AVDictionary **options)> avformat_find_stream_info;
std::function<int(AVFormatContext *s, AVPacket *pkt)> av_read_frame;
std::function<int(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)>
av_seek_frame;
std::function<unsigned()> 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 *(AVCodecID id)> avcodec_find_decoder;
std::function<AVCodecContext *(const AVCodec *codec)> avcodec_alloc_context3;
std::function<int(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)>
avcodec_open2;
std::function<void(AVCodecContext **avctx)> avcodec_free_context;
std::function<AVPacket *()> av_packet_alloc;
std::function<void(AVPacket **pkt)> av_packet_free;
std::function<void(AVPacket *pkt)> av_init_packet;
std::function<void(AVPacket *pkt)> av_packet_unref;
std::function<void(AVCodecContext *avctx)> avcodec_flush_buffers;
std::function<unsigned()> avcodec_version;
std::function<const char *(AVCodecID id)> avcodec_get_name;
std::function<AVCodecParameters *()> 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<int(AVCodecContext *avctx, const AVPacket *avpkt)> avcodec_send_packet;
std::function<int(AVCodecContext *avctx, AVFrame *frame)> avcodec_receive_frame;
std::function<int(AVCodecContext *codec, const AVCodecParameters *par)>
avcodec_parameters_to_context;
std::function<void()> 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<AVFrame *()> av_frame_alloc;
std::function<void(AVFrame **frame)> av_frame_free;
std::function<void(size_t size)> av_mallocz;
std::function<unsigned()> avutil_version;
std::function<int(AVDictionary **pm, const char *key, const char *value, int flags)>
av_dict_set;
std::function<AVDictionaryEntry*(
AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)>
av_dict_get;
std::function<AVFrameSideData *(const AVFrame *frame, AVFrameSideDataType type)>
av_frame_get_side_data;
std::function<AVDictionary *(const AVFrame *frame)> av_frame_get_metadata;
std::function<void(void (*callback)(void *, int, const char *, va_list))> av_log_set_callback;
std::function<void(int level)> av_log_set_level;
std::function<AVPixFmtDescriptor *(AVPixelFormat pix_fmt)> av_pix_fmt_desc_get;
std::function<AVPixFmtDescriptor *(const AVPixFmtDescriptor *prev)> av_pix_fmt_desc_next;
std::function<AVPixelFormat(const AVPixFmtDescriptor *desc)> 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<unsigned()> 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