Skip to content

Commit

Permalink
Start rework on the ffmpeg integration. Now getting ffmpeg from a path.
Browse files Browse the repository at this point in the history
  • Loading branch information
ChristianFeldmann committed Sep 25, 2023
1 parent 5881fbf commit b2109c8
Show file tree
Hide file tree
Showing 16 changed files with 265 additions and 341 deletions.
1 change: 1 addition & 0 deletions YUViewLib/src/common/FileInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,5 @@ struct InfoData
QString title{};
QList<InfoItem> items{};
};

Q_DECLARE_METATYPE(InfoData)
31 changes: 29 additions & 2 deletions YUViewLib/src/common/Functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@

#include "Functions.h"

#include <QCoreApplication>
#include <QSettings>
#include <QThread>

#ifdef Q_OS_MAC
#include <sys/sysctl.h>
#include <sys/types.h>
Expand All @@ -43,8 +47,6 @@

#include <algorithm>

#include <QThread>

namespace functions
{

Expand Down Expand Up @@ -153,6 +155,31 @@ QString formatDataSize(double size, bool isBits)
return valueString;
}

std::vector<std::filesystem::path> getDefaultLibrarySearchPaths()
{
std::vector<std::filesystem::path> paths;

{
QSettings settings;
auto decoderSearchPath = settings.value("SearchPath", "").toString().toStdString();
if (!decoderSearchPath.empty())
paths.push_back(decoderSearchPath);
}

paths.push_back(std::filesystem::current_path());
paths.push_back(std::filesystem::current_path() / "ffmpeg");
paths.push_back(std::filesystem::current_path() / "decoder");

const auto appPath = std::filesystem::path(QCoreApplication::applicationDirPath().toStdString());
paths.push_back(appPath);
paths.push_back(appPath / "ffmpeg");
paths.push_back(appPath / "decoder");

paths.push_back({});

return paths;
}

QStringList toQStringList(const std::vector<std::string> &stringVec)
{
QStringList list;
Expand Down
3 changes: 3 additions & 0 deletions YUViewLib/src/common/Functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@

#include <common/Typedef.h>

#include <filesystem>
#include <optional>

namespace functions
Expand Down Expand Up @@ -62,6 +63,8 @@ QStringList getThemeColors(QString themeName);
// compatible.
QString formatDataSize(double size, bool isBits = false);

std::vector<std::filesystem::path> getDefaultLibrarySearchPaths();

QStringList toQStringList(const std::vector<std::string> &stringVec);
std::string toLower(std::string str);

Expand Down
16 changes: 15 additions & 1 deletion YUViewLib/src/common/Typedef.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,6 @@ template <typename T> using vector4d = std::vector<vector3d<T>>;
template <typename T, size_t N> using array = std::array<T, N>;
template <typename T, size_t N1, size_t N2> using array2d = std::array<std::array<T, N2>, N1>;


template <typename T> int indexInVec(const std::vector<T> &vec, const T &item)
{
auto it = std::find(vec.begin(), vec.end(), item);
Expand Down Expand Up @@ -255,6 +254,21 @@ template <typename T> struct Range
}
};

class SuccessOrErrorMessage
{
public:
SuccessOrErrorMessage() = default;
SuccessOrErrorMessage(bool success) { this->success = success; }
SuccessOrErrorMessage(std::string errorMessage)
{
this->success = false;
this->errorMessage = errorMessage;
}
explicit operator bool() const { return this->success; };
bool success{false};
std::string errorMessage;
};

struct Ratio
{
int num{};
Expand Down
8 changes: 3 additions & 5 deletions YUViewLib/src/decoder/decoderBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,7 @@ class decoderBase
bool errorInDecoder() const { return decoderState == DecoderState::Error; }
QString decoderErrorString() const { return errorString; }

// Get the name, filename and full path to the decoder library(s) that is/are being used.
// The length of the list must be a multiple of 3 (name, libName, fullPath)
virtual QStringList getLibraryPaths() const = 0;
virtual std::vector<InfoItem> getDecoderInfo() const = 0;

// Get the decoder name (everyting that is needed to identify the decoder library) and the codec
// that is being decoded. If needed, also version information (like HM 16.4)
Expand Down Expand Up @@ -182,9 +180,9 @@ class decoderBaseSingleLib : public decoderBase
decoderBaseSingleLib(bool cachingDecoder = false) : decoderBase(cachingDecoder){};
virtual ~decoderBaseSingleLib(){};

QStringList getLibraryPaths() const override
std::vector<InfoItem> getDecoderInfo() const override
{
return QStringList() << getDecoderName() << library.fileName() << library.fileName();
return {{this->getDecoderName(), this->library.fileName(), this->library.fileName()}};
}

protected:
Expand Down
19 changes: 17 additions & 2 deletions YUViewLib/src/decoder/decoderFFmpeg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ decoderFFmpeg::decoderFFmpeg(FFmpeg::AVCodecIDWrapper codecID,
{
// The libraries are only loaded on demand. This way a FFmpegLibraries instance can exist without
// loading the libraries which is slow and uses a lot of memory.
this->ff.loadFFmpegLibraries();
this->ff.loadFFmpegLibraries(functions::getDefaultLibrarySearchPaths());
if (!this->ff.loadingSuccessfull())
return;

Expand Down Expand Up @@ -99,7 +99,7 @@ decoderFFmpeg::decoderFFmpeg(FFmpeg::AVCodecParametersWrapper codecpar, bool cac
{
// The libraries are only loaded on demand. This way a FFmpegLibraries instance can exist without
// loading the libraries which is slow and uses a lot of memory.
this->ff.loadFFmpegLibraries();
this->ff.loadFFmpegLibraries(functions::getDefaultLibrarySearchPaths());
if (!this->ff.loadingSuccessfull())
return;

Expand Down Expand Up @@ -319,6 +319,21 @@ bool decoderFFmpeg::pushData(QByteArray &data)
return this->pushAVPacket(this->raw_pkt);
}

std::vector<InfoItem> decoderFFmpeg::getDecoderInfo() const
{
const auto libraryPaths = this->ff.getLibraryPaths();

const auto avformatPath = QString::fromStdString(libraryPaths.avFormatPath);
const auto avcodecPath = QString::fromStdString(libraryPaths.avCodecPath);
const auto avutilPath = QString::fromStdString(libraryPaths.avUtilPath);
const auto swresamplePath = QString::fromStdString(libraryPaths.swResamplePath);

return {InfoItem("AVFormat", avformatPath),
InfoItem("AVCodec", avcodecPath),
InfoItem("AVUtil", avutilPath),
InfoItem("SWResample", swresamplePath)};
}

bool decoderFFmpeg::pushAVPacket(FFmpeg::AVPacketWrapper &pkt)
{
if (this->decoderState != DecoderState::NeedsMoreData)
Expand Down
6 changes: 3 additions & 3 deletions YUViewLib/src/decoder/decoderFFmpeg.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ class decoderFFmpeg : public decoderBase
// What statistics do we support?
void fillStatisticList(stats::StatisticsData &statisticsData) const override;

QStringList getLibraryPaths() const override { return ff.getLibPaths(); }
QString getDecoderName() const override { return "FFmpeg"; }
QString getCodecName() const override { return this->codecName; }
std::vector<InfoItem> getDecoderInfo() const override;
QString getDecoderName() const override { return "FFmpeg"; }
QString getCodecName() const override { return this->codecName; }

static QStringList getLogMessages() { return FFmpeg::FFmpegVersionHandler::getFFmpegLog(); }

Expand Down
96 changes: 25 additions & 71 deletions YUViewLib/src/ffmpeg/FFmpegLibraryFunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,23 +182,21 @@ FFmpegLibraryFunctions::~FFmpegLibraryFunctions()
this->unloadAllLibraries();
}

bool FFmpegLibraryFunctions::loadFFmpegLibraryInPath(QString path, LibraryVersion &libraryVersion)
SuccessOrErrorMessage
FFmpegLibraryFunctions::loadFFmpegLibraryInPath(const std::filesystem::path &path,
const LibraryVersion & libraryVersion)
{
// We will load the following libraries (in this order):
// avutil, swresample, avcodec, avformat.

if (!path.isEmpty())
std::filesystem::path absolutePath;
if (!path.empty())
{
QDir givenPath(path);
if (!givenPath.exists())
{
this->log("The given path is invalid");
return false;
}
if (!std::filesystem::exists(path))
return SuccessOrErrorMessage("The given path is invalid");

// Get the absolute path
path = givenPath.absolutePath() + "/";
this->log("Absolute path " + path);
absolutePath = std::filesystem::absolute(path);
this->log("Absolute path " + QString::fromStdString(absolutePath.string()));
}

// The ffmpeg libraries are named using a major version number. E.g: avutil-55.dll on windows.
Expand All @@ -224,9 +222,9 @@ bool FFmpegLibraryFunctions::loadFFmpegLibraryInPath(QString path, LibraryVersio
constructLibName = "lib%1.%2.dylib";

auto loadLibrary =
[this, &constructLibName, &path](QLibrary &lib, QString libName, unsigned version) {
[this, &constructLibName, &absolutePath](QLibrary &lib, QString libName, unsigned version) {
auto filename = constructLibName.arg(libName).arg(version);
lib.setFileName(path + filename);
lib.setFileName(QString::fromStdString(absolutePath.string()) + filename);
auto success = lib.load();
this->log("Loading library " + filename + (success ? " succeded" : " failed"));
return success;
Expand Down Expand Up @@ -260,40 +258,6 @@ bool FFmpegLibraryFunctions::loadFFmpegLibraryInPath(QString path, LibraryVersio
return success;
}

bool FFmpegLibraryFunctions::loadFFMpegLibrarySpecific(QString avFormatLib,
QString avCodecLib,
QString avUtilLib,
QString swResampleLib)
{
this->unloadAllLibraries();

auto loadLibrary = [this](QLibrary &lib, QString libPath) {
lib.setFileName(libPath);
auto success = lib.load();
this->log("Loading library " + libPath + (success ? " succeded" : " failed"));
return success;
};

auto success = (loadLibrary(this->libAvutil, avUtilLib) && //
loadLibrary(this->libSwresample, swResampleLib) && //
loadLibrary(this->libAvcodec, avCodecLib) && //
loadLibrary(this->libAvformat, avFormatLib));

if (!success)
{
this->unloadAllLibraries();
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));
this->log(QString("Binding functions ") + (success ? "successfull" : "failed"));

return success;
}

void FFmpegLibraryFunctions::addLibNamesToList(QString libName,
QStringList & l,
const QLibrary &lib) const
Expand All @@ -320,30 +284,20 @@ void FFmpegLibraryFunctions::unloadAllLibraries()
this->libAvformat.unload();
}

QStringList FFmpegLibraryFunctions::getLibPaths() const
LibraryPaths FFmpegLibraryFunctions::getLibraryPaths() const
{
QStringList libPaths;

auto addName = [&libPaths](QString name, const QLibrary &lib) {
libPaths.append(name);
if (lib.isLoaded())
{
libPaths.append(lib.fileName());
libPaths.append(lib.fileName());
}
else
{
libPaths.append("None");
libPaths.append("None");
}
};

addName("AVCodec", this->libAvcodec);
addName("AVFormat", this->libAvformat);
addName("AVUtil", this->libAvutil);
addName("SwResample", this->libSwresample);

return libPaths;
LibraryPaths paths;

if (this->libAvformat.isLoaded())
paths.avCodecPath = this->libAvformat.fileName().toStdString();
if (this->libAvcodec.isLoaded())
paths.avCodecPath = this->libAvcodec.fileName().toStdString();
if (this->libAvutil.isLoaded())
paths.avCodecPath = this->libAvutil.fileName().toStdString();
if (this->libSwresample.isLoaded())
paths.avCodecPath = this->libSwresample.fileName().toStdString();

return paths;
}

void FFmpegLibraryFunctions::log(QString message)
Expand All @@ -352,4 +306,4 @@ void FFmpegLibraryFunctions::log(QString message)
this->logList->append(message);
}

} // namespace FFmpeg
} // namespace FFmpeg
21 changes: 13 additions & 8 deletions YUViewLib/src/ffmpeg/FFmpegLibraryFunctions.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,25 +35,30 @@
#include "FFMpegLibrariesTypes.h"
#include <QLibrary>
#include <common/Typedef.h>
#include <filesystem>

namespace FFmpeg
{

struct LibraryPaths
{
std::string avFormatPath;
std::string avCodecPath;
std::string avUtilPath;
std::string swResamplePath;
};

class FFmpegLibraryFunctions
{
public:
FFmpegLibraryFunctions() = default;
~FFmpegLibraryFunctions();

// Load the FFmpeg libraries from the given path.
bool loadFFmpegLibraryInPath(QString path, LibraryVersion &libraryVersion);
// Try to load the 4 given specific libraries
bool loadFFMpegLibrarySpecific(QString avFormatLib,
QString avCodecLib,
QString avUtilLib,
QString swResampleLib);
SuccessOrErrorMessage loadFFmpegLibraryInPath(const std::filesystem::path &path,
const LibraryVersion & libraryVersion);

QStringList getLibPaths() const;
LibraryPaths getLibraryPaths() const;

struct AvFormatFunctions
{
Expand Down Expand Up @@ -104,7 +109,7 @@ class FFmpegLibraryFunctions
std::function<unsigned()> avutil_version;
std::function<int(AVDictionary **pm, const char *key, const char *value, int flags)>
av_dict_set;
std::function<AVDictionaryEntry*(
std::function<AVDictionaryEntry *(
AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)>
av_dict_get;
std::function<AVFrameSideData *(const AVFrame *frame, AVFrameSideDataType type)>
Expand Down
Loading

0 comments on commit b2109c8

Please sign in to comment.