Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/479 lib dav1d support #484

Draft
wants to merge 15 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
61 changes: 61 additions & 0 deletions YUViewLib/src/common/Functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,67 @@ std::string toLower(std::string str)
return str;
}

std::string to_string(const Size &size)
{
return std::to_string(size.width) + "x" + std::to_string(size.height);
}

std::string to_string(const StringVec &items, const std::string &seperator)
{
std::string str;
auto it = items.begin();
while (it != items.end())
{
if (it != items.begin())
str += seperator;
str += *it;
++it;
}
return str;
}

std::string vstring(const char *format, va_list vargs)
{
std::string result;
va_list args_copy;

va_copy(args_copy, vargs);

int len = vsnprintf(nullptr, 0, format, vargs);
if (len < 0)
{
va_end(args_copy);
throw std::runtime_error("vsnprintf error");
}

if (len > 0)
{
result.resize(len);
vsnprintf(result.data(), len + 1, format, args_copy);
}

va_end(args_copy);

return result;
}

std::string formatString(std::string format, const std::initializer_list<std::string> &arguments)
{
int counter = 0;
for (auto argument : arguments)
{
const auto toReplace = "%" + std::to_string(counter);
auto replacePos = format.find(toReplace);
if (replacePos == std::string::npos)
return format;

format.replace(replacePos, 2, argument);

++counter;
}
return format;
}

std::optional<unsigned long> toUnsigned(const std::string &text)
{
try
Expand Down
25 changes: 23 additions & 2 deletions YUViewLib/src/common/Functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,29 @@ QStringList getThemeColors(QString themeName);
// compatible.
QString formatDataSize(double size, bool isBits = false);

QStringList toQStringList(const std::vector<std::string> &stringVec);
std::string toLower(std::string str);
QStringList toQStringList(const std::vector<std::string> &stringVec);
[[nodiscard]] std::string toLower(std::string str);
[[nodiscard]] std::string to_string(const Size &size);
[[nodiscard]] std::string to_string(const StringVec &items, const std::string &seperator = ", ");
[[nodiscard]] std::string vstring(const char *format, va_list vargs);
[[nodiscard]] std::string formatString(std::string format,
const std::initializer_list<std::string> &arguments);

template <typename T>
[[nodiscard]] std::string to_string(const std::vector<T> &items,
const std::string & seperator = ", ")
{
std::string str;
auto it = items.begin();
while (it != items.end())
{
if (it != items.begin())
str += seperator;
str += std::to_string(*it);
++it;
}
return str;
}

inline std::string boolToString(bool b)
{
Expand Down
27 changes: 27 additions & 0 deletions YUViewLib/src/common/Typedef.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ typedef std::pair<int, int> IntPair;
typedef std::pair<unsigned, unsigned> UIntPair;
typedef std::pair<std::string, std::string> StringPair;
typedef std::vector<StringPair> StringPairVec;
typedef std::vector<std::string> StringVec;

/// ---- Legacy types that will be replaced
typedef QPair<QString, QString> QStringPair;
Expand Down Expand Up @@ -314,6 +315,32 @@ struct Offset
int y{};
};

struct Rational
{
bool operator!=(const Rational &second) const
{
const auto a = int64_t(this->num) * int64_t(second.den);
const auto b = int64_t(this->den) * int64_t(second.num);
return a != b;
}

int num{};
int den{};
};

struct FileStartEndPos
{
int64_t start{};
int64_t end{};
};

static std::string to_string(const FileStartEndPos &fileStartEndPos)
{
std::ostringstream ss;
ss << "(" << fileStartEndPos.start << ", " << fileStartEndPos.end << ")";
return ss.str();
}

// A list of value pair lists, where every list has a string (title)
class ValuePairListSets : public QList<QPair<QString, QStringPairList>>
{
Expand Down
97 changes: 57 additions & 40 deletions YUViewLib/src/decoder/decoderBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,43 @@
#include <QDir>
#include <QSettings>

using namespace std::string_literals;

namespace decoder
{

namespace
{

std::string getLibSearchPathFromSettings()
{
QSettings settings;
settings.beginGroup("Decoders");
auto searchPath = settings.value("SearchPath", "").toString().toStdString();
if (searchPath.back() != '/')
searchPath += "/";
settings.endGroup();
return searchPath;
}

StringVec getPathsToTry(const std::string &libName)
{
const auto currentPath = std::filesystem::absolute(std::filesystem::current_path()).string();
const auto currentAppPath = QCoreApplication::applicationDirPath().toStdString();

return {getLibSearchPathFromSettings() + libName,
currentPath + "/" + libName,
currentPath + "/decoder/" + libName,
currentPath + "/libde265/" + libName, // for legacy installations before the decoders were
// moved to the "decoders" folder
currentAppPath + "/" + libName,
currentAppPath + "/decoder/" + libName,
currentAppPath + "/libde265/" + libName,
libName}; // Try the system directories.
}

} // namespace

// Debug the decoder ( 0:off 1:interactive decoder only 2:caching decoder only 3:both)
#define DECODERBASE_DEBUG_OUTPUT 0
#if DECODERBASE_DEBUG_OUTPUT && !NDEBUG
Expand Down Expand Up @@ -97,18 +131,28 @@ stats::FrameTypeData decoderBase::getCurrentFrameStatsForType(int typeId) const
return statisticsData->getFrameTypeData(typeId);
}

void decoderBaseSingleLib::loadDecoderLibrary(QString specificLibrary)
void decoderBase::setError(const std::string &reason)
{
this->decoderState = DecoderState::Error;
this->errorString = reason;
}

bool decoderBase::setErrorB(const std::string &reason)
{
this->setError(reason);
return false;
}

void decoderBaseSingleLib::loadDecoderLibrary(const std::string &specificLibrary)
{
// Try to load the HM library from the current working directory
// Unfortunately relative paths like this do not work: (at least on windows)
// library.setFileName(".\\libde265");

bool libLoaded = false;

// Try the specific library first
this->library.setFileName(specificLibrary);
this->library.setFileName(QString::fromStdString(specificLibrary));
this->libraryPath = specificLibrary;
libLoaded = this->library.load();
auto libLoaded = this->library.load();

if (!libLoaded)
{
Expand All @@ -117,34 +161,13 @@ void decoderBaseSingleLib::loadDecoderLibrary(QString specificLibrary)
// the decLibXXX.so file first. Since this has been compiled for linux
// it will fail and not even try to open the decLixXXX.dylib.
// On windows and linux ommitting the extension works
auto libNames = getLibraryNames();

// Get the additional search path from the settings
QSettings settings;
settings.beginGroup("Decoders");
auto searchPath = settings.value("SearchPath", "").toString();
if (!searchPath.endsWith("/"))
searchPath.append("/");
searchPath.append("%1");
settings.endGroup();

auto const libPaths = QStringList()
<< searchPath << QDir::currentPath() + "/%1"
<< QDir::currentPath() + "/decoder/%1"
<< QDir::currentPath() +
"/libde265/%1" // for legacy installations before the decoders were
// moved to the "decoders" folder
<< QCoreApplication::applicationDirPath() + "/%1"
<< QCoreApplication::applicationDirPath() + "/decoder/%1"
<< QCoreApplication::applicationDirPath() + "/libde265/%1"
<< "%1"; // Try the system directories.

for (auto &libName : libNames)
for (const auto &libName : this->getLibraryNames())
{
for (auto &libPath : libPaths)
for (auto &libPath : getPathsToTry(libName))
{
this->library.setFileName(libPath.arg(libName));
this->libraryPath = libPath.arg(libName);
this->library.setFileName(QString::fromStdString(libPath));
this->libraryPath = libPath;
libLoaded = library.load();
if (libLoaded)
break;
Expand All @@ -157,21 +180,15 @@ void decoderBaseSingleLib::loadDecoderLibrary(QString specificLibrary)
if (!libLoaded)
{
this->libraryPath.clear();
auto error = "Error loading library: " + this->library.errorString() + "\n";
auto error = "Error loading library: "s + this->library.errorString().toStdString() + "\n";
error += "We could not load one of the supported decoder library (";
auto libNames = this->getLibraryNames();
for (int i = 0; i < libNames.count(); i++)
{
if (i == 0)
error += libNames[0];
else
error += ", " + libNames[i];
}
error += ").\n";
error += to_string(libNames);
error += "\n";
error += "We do not ship all of the decoder libraries.\n";
error += "You can find download links in Help->Downloads.";
return this->setError(error);
this->setError(error);
return;
}

this->resolveLibraryFunctionPointers();
Expand Down
52 changes: 22 additions & 30 deletions YUViewLib/src/decoder/decoderBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,11 @@ class decoderBase

// Does the loaded library support the extraction of prediction/residual data?
// These are the default implementations. Overload if a decoder can support more signals.
virtual int nrSignalsSupported() const { return 1; }
virtual QStringList getSignalNames() const { return QStringList() << "Reconstruction"; }
virtual bool isSignalDifference(int signalID) const;
virtual void setDecodeSignal(int signalID, bool &decoderResetNeeded);
int getDecodeSignal() const { return this->decodeSignal; }
virtual int nrSignalsSupported() const { return 1; }
virtual StringVec getSignalNames() const { return {"Reconstruction"}; }
virtual bool isSignalDifference(int signalID) const;
virtual void setDecodeSignal(int signalID, bool &decoderResetNeeded);
int getDecodeSignal() const { return this->decodeSignal; }

// -- The decoding interface
// If the current frame is valid, the current frame can be retrieved using getRawFrameData.
Expand All @@ -124,24 +124,24 @@ class decoderBase

// Get the statistics values for the current frame. In order to enable statistics retrievel,
// activate it, reset the decoder and decode to the current frame again.
bool statisticsSupported() const { return internalsSupported; }
bool statisticsEnabled() const { return statisticsData != nullptr; }
bool statisticsSupported() const { return this->internalsSupported; }
bool statisticsEnabled() const { return this->statisticsData != nullptr; }
void enableStatisticsRetrieval(stats::StatisticsData *s) { this->statisticsData = s; }
stats::FrameTypeData getCurrentFrameStatsForType(int typeIdx) const;
virtual void fillStatisticList(stats::StatisticsData &) const {};

// Error handling
bool errorInDecoder() const { return decoderState == DecoderState::Error; }
QString decoderErrorString() const { return errorString; }
bool errorInDecoder() const { return this->decoderState == DecoderState::Error; }
std::string decoderErrorString() const { return this->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 StringVec getLibraryPaths() 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)
virtual QString getDecoderName() const = 0;
virtual QString getCodecName() const = 0;
virtual std::string getDecoderName() const = 0;
virtual std::string getCodecName() const = 0;

protected:
DecoderState decoderState{DecoderState::NeedsMoreData};
Expand All @@ -157,18 +157,10 @@ class decoderBase
video::yuv::PixelFormatYUV formatYUV{};
video::rgb::PixelFormatRGB formatRGB{};

// Error handling
void setError(const QString &reason)
{
decoderState = DecoderState::Error;
errorString = reason;
}
bool setErrorB(const QString &reason)
{
setError(reason);
return false;
}
QString errorString{};
void setError(const std::string &reason);
bool setErrorB(const std::string &reason);

std::string errorString{};

// If set, fill it (if possible). The playlistItem has ownership of this.
stats::StatisticsData *statisticsData{};
Expand All @@ -182,20 +174,20 @@ class decoderBaseSingleLib : public decoderBase
decoderBaseSingleLib(bool cachingDecoder = false) : decoderBase(cachingDecoder){};
virtual ~decoderBaseSingleLib(){};

QStringList getLibraryPaths() const override
StringVec getLibraryPaths() const override
{
return QStringList() << getDecoderName() << library.fileName() << library.fileName();
return {this->getDecoderName(), this->library.fileName().toStdString()};
}

protected:
virtual void resolveLibraryFunctionPointers() = 0;
void loadDecoderLibrary(QString specificLibrary);
void loadDecoderLibrary(const std::string &specificLibrary);

// Get all possible names of the library that we will load
virtual QStringList getLibraryNames() const = 0;
virtual StringVec getLibraryNames() const = 0;

QLibrary library;
QString libraryPath{};
QLibrary library;
std::string libraryPath{};
};

} // namespace decoder