From b2109c8825521ea735c163dce52ff7e619701e09 Mon Sep 17 00:00:00 2001 From: Christian Feldmann Date: Mon, 25 Sep 2023 14:12:32 +0200 Subject: [PATCH] Start rework on the ffmpeg integration. Now getting ffmpeg from a path. --- YUViewLib/src/common/FileInfo.h | 1 + YUViewLib/src/common/Functions.cpp | 31 ++- YUViewLib/src/common/Functions.h | 3 + YUViewLib/src/common/Typedef.h | 16 +- YUViewLib/src/decoder/decoderBase.h | 8 +- YUViewLib/src/decoder/decoderFFmpeg.cpp | 19 +- YUViewLib/src/decoder/decoderFFmpeg.h | 6 +- .../src/ffmpeg/FFmpegLibraryFunctions.cpp | 96 +++------ YUViewLib/src/ffmpeg/FFmpegLibraryFunctions.h | 21 +- YUViewLib/src/ffmpeg/FFmpegVersionHandler.cpp | 97 ++------- YUViewLib/src/ffmpeg/FFmpegVersionHandler.h | 25 +-- .../src/filesource/FileSourceFFmpegFile.cpp | 2 +- .../src/filesource/FileSourceFFmpegFile.h | 2 +- .../playlistItemCompressedVideo.cpp | 21 +- YUViewLib/src/ui/SettingsDialog.cpp | 189 ++++++++---------- YUViewLib/src/ui/SettingsDialog.h | 69 +++---- 16 files changed, 265 insertions(+), 341 deletions(-) diff --git a/YUViewLib/src/common/FileInfo.h b/YUViewLib/src/common/FileInfo.h index 49a7e924b..fce0dba3e 100644 --- a/YUViewLib/src/common/FileInfo.h +++ b/YUViewLib/src/common/FileInfo.h @@ -66,4 +66,5 @@ struct InfoData QString title{}; QList items{}; }; + Q_DECLARE_METATYPE(InfoData) diff --git a/YUViewLib/src/common/Functions.cpp b/YUViewLib/src/common/Functions.cpp index 07a7b7b0f..5a6403a85 100644 --- a/YUViewLib/src/common/Functions.cpp +++ b/YUViewLib/src/common/Functions.cpp @@ -32,6 +32,10 @@ #include "Functions.h" +#include +#include +#include + #ifdef Q_OS_MAC #include #include @@ -43,8 +47,6 @@ #include -#include - namespace functions { @@ -153,6 +155,31 @@ QString formatDataSize(double size, bool isBits) return valueString; } +std::vector getDefaultLibrarySearchPaths() +{ + std::vector 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 &stringVec) { QStringList list; diff --git a/YUViewLib/src/common/Functions.h b/YUViewLib/src/common/Functions.h index 667c7fe41..e07d7d838 100644 --- a/YUViewLib/src/common/Functions.h +++ b/YUViewLib/src/common/Functions.h @@ -34,6 +34,7 @@ #include +#include #include namespace functions @@ -62,6 +63,8 @@ QStringList getThemeColors(QString themeName); // compatible. QString formatDataSize(double size, bool isBits = false); +std::vector getDefaultLibrarySearchPaths(); + QStringList toQStringList(const std::vector &stringVec); std::string toLower(std::string str); diff --git a/YUViewLib/src/common/Typedef.h b/YUViewLib/src/common/Typedef.h index 201ccaf9f..c1a6b8c59 100644 --- a/YUViewLib/src/common/Typedef.h +++ b/YUViewLib/src/common/Typedef.h @@ -227,7 +227,6 @@ template using vector4d = std::vector>; template using array = std::array; template using array2d = std::array, N1>; - template int indexInVec(const std::vector &vec, const T &item) { auto it = std::find(vec.begin(), vec.end(), item); @@ -255,6 +254,21 @@ template 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{}; diff --git a/YUViewLib/src/decoder/decoderBase.h b/YUViewLib/src/decoder/decoderBase.h index 1b5c18ae1..cadc3f17e 100644 --- a/YUViewLib/src/decoder/decoderBase.h +++ b/YUViewLib/src/decoder/decoderBase.h @@ -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 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) @@ -182,9 +180,9 @@ class decoderBaseSingleLib : public decoderBase decoderBaseSingleLib(bool cachingDecoder = false) : decoderBase(cachingDecoder){}; virtual ~decoderBaseSingleLib(){}; - QStringList getLibraryPaths() const override + std::vector getDecoderInfo() const override { - return QStringList() << getDecoderName() << library.fileName() << library.fileName(); + return {{this->getDecoderName(), this->library.fileName(), this->library.fileName()}}; } protected: diff --git a/YUViewLib/src/decoder/decoderFFmpeg.cpp b/YUViewLib/src/decoder/decoderFFmpeg.cpp index 89c0ec69e..843f6f57d 100644 --- a/YUViewLib/src/decoder/decoderFFmpeg.cpp +++ b/YUViewLib/src/decoder/decoderFFmpeg.cpp @@ -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; @@ -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; @@ -319,6 +319,21 @@ bool decoderFFmpeg::pushData(QByteArray &data) return this->pushAVPacket(this->raw_pkt); } +std::vector 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) diff --git a/YUViewLib/src/decoder/decoderFFmpeg.h b/YUViewLib/src/decoder/decoderFFmpeg.h index 6f2a33571..d35fd8d10 100644 --- a/YUViewLib/src/decoder/decoderFFmpeg.h +++ b/YUViewLib/src/decoder/decoderFFmpeg.h @@ -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 getDecoderInfo() const override; + QString getDecoderName() const override { return "FFmpeg"; } + QString getCodecName() const override { return this->codecName; } static QStringList getLogMessages() { return FFmpeg::FFmpegVersionHandler::getFFmpegLog(); } diff --git a/YUViewLib/src/ffmpeg/FFmpegLibraryFunctions.cpp b/YUViewLib/src/ffmpeg/FFmpegLibraryFunctions.cpp index d4ffa014c..051a9465b 100644 --- a/YUViewLib/src/ffmpeg/FFmpegLibraryFunctions.cpp +++ b/YUViewLib/src/ffmpeg/FFmpegLibraryFunctions.cpp @@ -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. @@ -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; @@ -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 @@ -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) @@ -352,4 +306,4 @@ void FFmpegLibraryFunctions::log(QString message) this->logList->append(message); } -} // namespace FFmpeg \ No newline at end of file +} // namespace FFmpeg diff --git a/YUViewLib/src/ffmpeg/FFmpegLibraryFunctions.h b/YUViewLib/src/ffmpeg/FFmpegLibraryFunctions.h index 4f0487a62..946016275 100644 --- a/YUViewLib/src/ffmpeg/FFmpegLibraryFunctions.h +++ b/YUViewLib/src/ffmpeg/FFmpegLibraryFunctions.h @@ -35,10 +35,19 @@ #include "FFMpegLibrariesTypes.h" #include #include +#include namespace FFmpeg { +struct LibraryPaths +{ + std::string avFormatPath; + std::string avCodecPath; + std::string avUtilPath; + std::string swResamplePath; +}; + class FFmpegLibraryFunctions { public: @@ -46,14 +55,10 @@ class FFmpegLibraryFunctions ~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 { @@ -104,7 +109,7 @@ class FFmpegLibraryFunctions std::function avutil_version; std::function av_dict_set; - std::function av_dict_get; std::function diff --git a/YUViewLib/src/ffmpeg/FFmpegVersionHandler.cpp b/YUViewLib/src/ffmpeg/FFmpegVersionHandler.cpp index 0cb91f739..f465ff34d 100644 --- a/YUViewLib/src/ffmpeg/FFmpegVersionHandler.cpp +++ b/YUViewLib/src/ffmpeg/FFmpegVersionHandler.cpp @@ -327,7 +327,7 @@ void FFmpegVersionHandler::avLogCallback(void *, int level, const char *fmt, va_ QString(" - L%1 - ").arg(level) + msg); } -void FFmpegVersionHandler::loadFFmpegLibraries() +void FFmpegVersionHandler::loadFFmpegLibraries(std::vector searchPaths) { if (this->librariesLoaded) return; @@ -338,46 +338,26 @@ void FFmpegVersionHandler::loadFFmpegLibraries() // First try the specific FFMpeg libraries (if set) QSettings settings; settings.beginGroup("Decoders"); - auto avFormatLib = settings.value("FFmpeg.avformat", "").toString(); - auto avCodecLib = settings.value("FFmpeg.avcodec", "").toString(); - auto avUtilLib = settings.value("FFmpeg.avutil", "").toString(); - auto swResampleLib = settings.value("FFmpeg.swresample", "").toString(); - if (!avFormatLib.isEmpty() && // - !avCodecLib.isEmpty() && // - !avUtilLib.isEmpty() && // - !swResampleLib.isEmpty()) + auto ffmpegPath = settings.value("FFmpeg.path", "").toString().toStdString(); + if (!ffmpegPath.empty()) { this->log("Trying to load the libraries specified in the settings."); - this->librariesLoaded = - loadFFMpegLibrarySpecific(avFormatLib, avCodecLib, avUtilLib, swResampleLib); + const auto result = this->loadFFmpegLibraryInPath(ffmpegPath); + this->librariesLoaded = result.success; } else this->log("No ffmpeg libraries were specified in the settings."); if (!this->librariesLoaded) { - // Next, we will try some other paths / options - QStringList possibilites; - auto decoderSearchPath = settings.value("SearchPath", "").toString(); - if (!decoderSearchPath.isEmpty()) - possibilites.append(decoderSearchPath); // Try the specific search path (if one is set) - possibilites.append(QDir::currentPath() + "/"); // Try the current working directory - possibilites.append(QDir::currentPath() + "/ffmpeg/"); - possibilites.append(QCoreApplication::applicationDirPath() + - "/"); // Try the path of the YUView.exe - possibilites.append(QCoreApplication::applicationDirPath() + "/ffmpeg/"); - possibilites.append( - ""); // Just try to call QLibrary::load so that the system folder will be searched. - - for (auto path : possibilites) + for (const auto &path : searchPaths) { - if (path.isEmpty()) - this->log("Trying to load the libraries in the system path"); - else - this->log("Trying to load the libraries in the path " + path); + this->log("Trying to load the libraries in the path " + + QString::fromStdString(path.string())); - this->librariesLoaded = loadFFmpegLibraryInPath(path); - if (this->librariesLoaded) + auto result = loadFFmpegLibraryInPath(path); + this->librariesLoaded = result.success; + if (result.success) break; } } @@ -510,12 +490,13 @@ int FFmpegVersionHandler::seekBeginning(AVFormatContextWrapper &fmt) return lib.avformat.av_seek_frame(fmt.getFormatCtx(), -1, fmt.getStartTime(), 0); } -bool FFmpegVersionHandler::loadFFmpegLibraryInPath(QString path) +SuccessOrErrorMessage +FFmpegVersionHandler::loadFFmpegLibraryInPath(const std::filesystem::path path) { - bool success = false; + SuccessOrErrorMessage success; for (auto version : SupportedLibraryVersionCombinations) { - if (this->lib.loadFFmpegLibraryInPath(path, version)) + if (auto loadResult = this->lib.loadFFmpegLibraryInPath(path, version)) { this->log(QString("Checking versions avutil %1, swresample %2, avcodec %3, avformat %4") .arg(version.avutil.major) @@ -538,53 +519,11 @@ bool FFmpegVersionHandler::loadFFmpegLibraryInPath(QString path) return success; } -bool FFmpegVersionHandler::loadFFMpegLibrarySpecific(QString avFormatLib, - QString avCodecLib, - QString avUtilLib, - QString swResampleLib) -{ - bool success = false; - for (auto version : SupportedLibraryVersionCombinations) - { - this->log(QString("Checking versions avutil %1, swresample %2, avcodec %3, avformat %4") - .arg(version.avutil.major) - .arg(version.swresample.major) - .arg(version.avcodec.major) - .arg(version.avformat.major)); - if (lib.loadFFMpegLibrarySpecific(avFormatLib, avCodecLib, avUtilLib, swResampleLib)) - { - this->log("Testing versions of the library. Currently looking for:"); - this->log(QString("avutil: %1.xx.xx").arg(version.avutil.major)); - this->log(QString("swresample: %1.xx.xx").arg(version.swresample.major)); - this->log(QString("avcodec: %1.xx.xx").arg(version.avcodec.major)); - this->log(QString("avformat: %1.xx.xx").arg(version.avformat.major)); - - if ((success = checkVersionWithLib(this->lib, version, this->logList))) - { - this->libVersion = addMinorAndMicroVersion(this->lib, version); - this->log("checking the library versions was successful."); - break; - } - } - } - - if (success && this->libVersion.avformat.major < 59) - this->lib.avformat.av_register_all(); - - return success; -} - -bool FFmpegVersionHandler::checkLibraryFiles(QString avCodecLib, - QString avFormatLib, - QString avUtilLib, - QString swResampleLib, - QStringList &logging) +SuccessOrErrorMessage +FFmpegVersionHandler::checkPathForUsableFFmpeg(const std::filesystem::path &path) { FFmpegVersionHandler handler; - bool success = - handler.loadFFMpegLibrarySpecific(avFormatLib, avCodecLib, avUtilLib, swResampleLib); - logging = handler.getLog(); - return success; + return handler.loadFFmpegLibraryInPath(path); } void FFmpegVersionHandler::enableLoggingWarning() diff --git a/YUViewLib/src/ffmpeg/FFmpegVersionHandler.h b/YUViewLib/src/ffmpeg/FFmpegVersionHandler.h index b916a246f..bc36ebc56 100644 --- a/YUViewLib/src/ffmpeg/FFmpegVersionHandler.h +++ b/YUViewLib/src/ffmpeg/FFmpegVersionHandler.h @@ -44,6 +44,7 @@ #include "FFMpegLibrariesTypes.h" #include "FFmpegLibraryFunctions.h" #include +#include namespace FFmpeg { @@ -55,11 +56,11 @@ class FFmpegVersionHandler ~FFmpegVersionHandler(); // Try to load the ffmpeg libraries and get all the function pointers. - void loadFFmpegLibraries(); + void loadFFmpegLibraries(std::vector searchPaths); bool loadingSuccessfull() const; - QStringList getLibPaths() const { return lib.getLibPaths(); } - QString getLibVersionString() const; + LibraryPaths getLibraryPaths() const { return this->lib.getLibraryPaths(); } + QString getLibVersionString() const; // Only these functions can be used to get valid versions of these wrappers (they have to use // ffmpeg functions to retrieve the needed information) @@ -112,12 +113,8 @@ class FFmpegVersionHandler FFmpegLibraryFunctions lib; static AVPixelFormat convertYUVAVPixelFormat(video::yuv::PixelFormatYUV fmt); - // Check if the given four files can be used to open FFmpeg. - static bool checkLibraryFiles(QString avCodecLib, - QString avFormatLib, - QString avUtilLib, - QString swResampleLib, - QStringList &logging); + + static SuccessOrErrorMessage checkPathForUsableFFmpeg(const std::filesystem::path &path); // Logging. By default we set the logging level of ffmpeg to AV_LOG_ERROR (Log errors and // everything worse) @@ -127,14 +124,8 @@ class FFmpegVersionHandler QStringList getLog() const { return logList; } private: - // Try to load the FFmpeg libraries from the given path. - // Try the system paths if no path is provided. This function can be called multiple times. - bool loadFFmpegLibraryInPath(QString path); - // Try to load the four specific library files - bool loadFFMpegLibrarySpecific(QString avFormatLib, - QString avCodecLib, - QString avUtilLib, - QString swResampleLib); + SuccessOrErrorMessage loadFFmpegLibraryInPath(const std::filesystem::path); + bool librariesLoaded{}; // Log what is happening when loading the libraries / opening files. diff --git a/YUViewLib/src/filesource/FileSourceFFmpegFile.cpp b/YUViewLib/src/filesource/FileSourceFFmpegFile.cpp index 43a8cb61f..11fd656d6 100644 --- a/YUViewLib/src/filesource/FileSourceFFmpegFile.cpp +++ b/YUViewLib/src/filesource/FileSourceFFmpegFile.cpp @@ -476,7 +476,7 @@ void FileSourceFFmpegFile::openFileAndFindVideoStream(QString fileName) { this->isFileOpened = false; - this->ff.loadFFmpegLibraries(); + this->ff.loadFFmpegLibraries(functions::getDefaultLibrarySearchPaths()); if (!this->ff.loadingSuccessfull()) return; diff --git a/YUViewLib/src/filesource/FileSourceFFmpegFile.h b/YUViewLib/src/filesource/FileSourceFFmpegFile.h index 0505def37..42e1ede45 100644 --- a/YUViewLib/src/filesource/FileSourceFFmpegFile.h +++ b/YUViewLib/src/filesource/FileSourceFFmpegFile.h @@ -63,7 +63,7 @@ class FileSourceFFmpegFile : public QObject bool atEnd() const { return endOfFile; } // Return the name, filename and full path of every library loaded - QStringList getLibraryPaths() const { return ff.getLibPaths(); } + FFmpeg::LibraryPaths getLibraryPaths() const { return this->ff.getLibraryPaths(); } // Get properties of the bitstream double getFramerate() const { return frameRate; } diff --git a/YUViewLib/src/playlistitem/playlistItemCompressedVideo.cpp b/YUViewLib/src/playlistitem/playlistItemCompressedVideo.cpp index 893840735..12d4481e3 100644 --- a/YUViewLib/src/playlistitem/playlistItemCompressedVideo.cpp +++ b/YUViewLib/src/playlistitem/playlistItemCompressedVideo.cpp @@ -472,12 +472,11 @@ InfoData playlistItemCompressedVideo::getInfo() const InfoItem("Reader", QString::fromStdString(InputFormatMapper.getName(this->inputFormat)))); if (this->inputFileFFmpegLoading) { - auto l = this->inputFileFFmpegLoading->getLibraryPaths(); - if (l.length() % 3 == 0) - { - for (int i = 0; i < l.length() / 3; i++) - info.items.append(InfoItem(l[i * 3], l[i * 3 + 1], l[i * 3 + 2])); - } + const auto libraryPaths = this->inputFileFFmpegLoading->getLibraryPaths(); + info.items.append(InfoItem("AVFormat", QString::fromStdString(libraryPaths.avFormatPath))); + info.items.append(InfoItem("AVCodec", QString::fromStdString(libraryPaths.avCodecPath))); + info.items.append(InfoItem("AVUtil", QString::fromStdString(libraryPaths.avUtilPath))); + info.items.append(InfoItem("SWResample", QString::fromStdString(libraryPaths.swResamplePath))); } if (!this->unresolvableError) { @@ -491,12 +490,10 @@ InfoData playlistItemCompressedVideo::getInfo() const InfoItem("Num POCs", QString::number(nrFrames), "The number of pictures in the stream.")); if (this->decodingEnabled) { - auto l = loadingDecoder->getLibraryPaths(); - if (l.length() % 3 == 0) - { - for (int i = 0; i < l.length() / 3; i++) - info.items.append(InfoItem(l[i * 3], l[i * 3 + 1], l[i * 3 + 2])); - } + const auto decoderInfo = loadingDecoder->getDecoderInfo(); + for (const auto &infoItem : decoderInfo) + info.items.append(infoItem); + info.items.append(InfoItem("Decoder", this->loadingDecoder->getDecoderName())); info.items.append(InfoItem("Decoder", this->loadingDecoder->getCodecName())); info.items.append(InfoItem("Statistics", diff --git a/YUViewLib/src/ui/SettingsDialog.cpp b/YUViewLib/src/ui/SettingsDialog.cpp index 1c27ca33f..04c16ded1 100644 --- a/YUViewLib/src/ui/SettingsDialog.cpp +++ b/YUViewLib/src/ui/SettingsDialog.cpp @@ -49,6 +49,35 @@ #define MIN_CACHE_SIZE_IN_MB (20u) +namespace +{ + +QStringList getLibraryPath(QWidget *parent, QString currentFile, QString caption) +{ + // Use the currently selected dir or the dir to YUView if this one does not exist. + QFileInfo curFile(currentFile); + auto curDir = curFile.absoluteDir(); + if (!curDir.exists()) + curDir = QDir::current(); + + QFileDialog fileDialog(parent, caption); + fileDialog.setDirectory(curDir); + fileDialog.setFileMode(QFileDialog::ExistingFile); + if (is_Q_OS_LINUX) + fileDialog.setNameFilter("Library files (*.so.* *.so)"); + if (is_Q_OS_MAC) + fileDialog.setNameFilter("Library files (*.dylib)"); + if (is_Q_OS_WIN) + fileDialog.setNameFilter("Library files (*.dll)"); + + if (fileDialog.exec()) + return fileDialog.selectedFiles(); + + return {}; +} + +} // namespace + SettingsDialog::SettingsDialog(QWidget *parent) : QDialog(parent) { ui.setupUi(this); @@ -156,10 +185,7 @@ SettingsDialog::SettingsDialog(QWidget *parent) : QDialog(parent) ui.lineEditLibDav1d->setText(settings.value("libDav1dFile", "").toString()); ui.lineEditLibVTMFile->setText(settings.value("libVTMFile", "").toString()); ui.lineEditLibVVDecFile->setText(settings.value("libVVDecFile", "").toString()); - ui.lineEditAVFormat->setText(settings.value("FFmpeg.avformat", "").toString()); - ui.lineEditAVCodec->setText(settings.value("FFmpeg.avcodec", "").toString()); - ui.lineEditAVUtil->setText(settings.value("FFmpeg.avutil", "").toString()); - ui.lineEditSWResample->setText(settings.value("FFmpeg.swresample", "").toString()); + ui.lineEditFFmpegPath->setText(settings.value("FFmpeg.path", "").toString()); settings.endGroup(); } @@ -242,34 +268,10 @@ void SettingsDialog::on_pushButtonDecoderSelectPath_clicked() } } -QStringList SettingsDialog::getLibraryPath(QString currentFile, QString caption, bool multipleFiles) -{ - // Use the currently selected dir or the dir to YUView if this one does not exist. - QFileInfo curFile(currentFile); - QDir curDir = curFile.absoluteDir(); - if (!curDir.exists()) - curDir = QDir::current(); - - QFileDialog fileDialog(this, caption); - fileDialog.setDirectory(curDir); - fileDialog.setFileMode(multipleFiles ? QFileDialog::ExistingFiles : QFileDialog::ExistingFile); - if (is_Q_OS_LINUX) - fileDialog.setNameFilter("Library files (*.so.* *.so)"); - if (is_Q_OS_MAC) - fileDialog.setNameFilter("Library files (*.dylib)"); - if (is_Q_OS_WIN) - fileDialog.setNameFilter("Library files (*.dll)"); - - if (fileDialog.exec()) - return fileDialog.selectedFiles(); - - return {}; -} - void SettingsDialog::on_pushButtonLibde265SelectFile_clicked() { - QStringList newFiles = this->getLibraryPath(ui.lineEditLibde265File->text(), - "Please select the libde265 library file to use."); + const auto newFiles = getLibraryPath( + this, ui.lineEditLibde265File->text(), "Please select the libde265 library file to use."); if (newFiles.count() != 1) return; QString error; @@ -284,8 +286,8 @@ void SettingsDialog::on_pushButtonLibde265SelectFile_clicked() void SettingsDialog::on_pushButtonlibHMSelectFile_clicked() { - QStringList newFiles = this->getLibraryPath( - ui.lineEditLibHMFile->text(), "Please select the libHMDecoder library file to use."); + const auto newFiles = getLibraryPath( + this, ui.lineEditLibHMFile->text(), "Please select the libHMDecoder library file to use."); if (newFiles.count() != 1) return; QString error; @@ -300,8 +302,8 @@ void SettingsDialog::on_pushButtonlibHMSelectFile_clicked() void SettingsDialog::on_pushButtonLibDav1dSelectFile_clicked() { - QStringList newFiles = this->getLibraryPath(ui.lineEditLibDav1d->text(), - "Please select the libDav1d library file to use."); + const auto newFiles = getLibraryPath( + this, ui.lineEditLibDav1d->text(), "Please select the libDav1d library file to use."); if (newFiles.count() != 1) return; QString error; @@ -316,8 +318,8 @@ void SettingsDialog::on_pushButtonLibDav1dSelectFile_clicked() void SettingsDialog::on_pushButtonLibVTMSelectFile_clicked() { - QStringList newFiles = this->getLibraryPath( - ui.lineEditLibVTMFile->text(), "Please select the libVTMDecoder library file to use."); + const auto newFiles = getLibraryPath( + this, ui.lineEditLibVTMFile->text(), "Please select the libVTMDecoder library file to use."); if (newFiles.count() != 1) return; QString error; @@ -332,8 +334,9 @@ void SettingsDialog::on_pushButtonLibVTMSelectFile_clicked() void SettingsDialog::on_pushButtonLibVVDecSelectFile_clicked() { - QStringList newFiles = this->getLibraryPath( - ui.lineEditLibVVDecFile->text(), "Please select the libVVDec decoder library file to use."); + const auto newFiles = getLibraryPath(this, + ui.lineEditLibVVDecFile->text(), + "Please select the libVVDec decoder library file to use."); if (newFiles.count() != 1) return; QString error; @@ -347,75 +350,59 @@ void SettingsDialog::on_pushButtonLibVVDecSelectFile_clicked() ui.lineEditLibVVDecFile->setText(newFiles[0]); } -void SettingsDialog::on_pushButtonFFMpegSelectFile_clicked() +void SettingsDialog::on_pushButtonFFMpegSelectPath_clicked() { - QStringList newFiles = this->getLibraryPath( - ui.lineEditAVFormat->text(), - "Please select the 4 FFmpeg libraries AVCodec, AVFormat, AVUtil and SWResample.", - true); - if (newFiles.empty()) + auto curDir = QDir(ui.lineEditFFmpegPath->text()); + if (!curDir.exists()) + curDir = QDir::current(); + + QFileDialog fileDialog(this, + tr("Please select the path to the shared ffmpeg libraries " + "(avformat, avcodec, avutil and swscale)")); + fileDialog.setDirectory(curDir); + fileDialog.setFileMode(QFileDialog::Directory); + + if (!fileDialog.exec()) return; - // Get the 4 libraries from the list - QString avCodecLib, avFormatLib, avUtilLib, swResampleLib; - if (newFiles.count() == 4) - { - for (auto file : newFiles) - { - QFileInfo fileInfo(file); - if (fileInfo.baseName().contains("avcodec", Qt::CaseInsensitive)) - avCodecLib = file; - if (fileInfo.baseName().contains("avformat", Qt::CaseInsensitive)) - avFormatLib = file; - if (fileInfo.baseName().contains("avutil", Qt::CaseInsensitive)) - avUtilLib = file; - if (fileInfo.baseName().contains("swresample", Qt::CaseInsensitive)) - swResampleLib = file; - } - } - if (avCodecLib.isEmpty() || avFormatLib.isEmpty() || avUtilLib.isEmpty() || - swResampleLib.isEmpty()) - { - QMessageBox::critical( - this, - "Error in file selection", - "Please select the four FFmpeg files AVCodec, AVFormat, AVUtil and SWresample."); + auto newDirectory = fileDialog.selectedFiles(); + + if (newDirectory.empty()) return; - } - // Try to open ffmpeg using the four libraries - QStringList logList; - if (!FFmpeg::FFmpegVersionHandler::checkLibraryFiles( - avCodecLib, avFormatLib, avUtilLib, swResampleLib, logList)) + const auto path = std::filesystem::path(newDirectory.first().toStdString()); + + const auto result = FFmpeg::FFmpegVersionHandler::checkPathForUsableFFmpeg(path); + if (result) { - QMessageBox::StandardButton b = QMessageBox::question( - this, - "Error opening the library", - "The selected file does not appear to be a usable ffmpeg avFormat library. \nWe have " - "collected a more detailed log. Do you want to save it to disk?"); - if (b == QMessageBox::Yes) - { - const auto filePath = - QFileDialog::getSaveFileName(this, "Select a destination for the log file."); - QFile logFile(filePath); - logFile.open(QIODevice::WriteOnly); - if (logFile.isOpen()) - { - QTextStream outputStream(&logFile); - for (auto l : logList) - outputStream << l << "\n"; - } - else - QMessageBox::information( - this, "Error opening file", "There was an error opening the log file " + filePath); - } + ui.lineEditFFmpegPath->setText(newDirectory.first()); } else { - ui.lineEditAVCodec->setText(avCodecLib); - ui.lineEditAVFormat->setText(avFormatLib); - ui.lineEditAVUtil->setText(avUtilLib); - ui.lineEditSWResample->setText(swResampleLib); + QMessageBox::information(this, + "Error opening ffmpeg in directory", + "We could not open the ffmpeg libraries in the given folder."); + // QMessageBox::StandardButton b = QMessageBox::question( + // this, + // "Error opening the library", + // "The selected file does not appear to be a usable ffmpeg avFormat library. \nWe have " + // "collected a more detailed log. Do you want to save it to disk?"); + // if (b == QMessageBox::Yes) + // { + // const auto filePath = + // QFileDialog::getSaveFileName(this, "Select a destination for the log file."); + // QFile logFile(filePath); + // logFile.open(QIODevice::WriteOnly); + // if (logFile.isOpen()) + // { + // QTextStream outputStream(&logFile); + // for (auto l : logList) + // outputStream << l << "\n"; + // } + // else + // QMessageBox::information( + // this, "Error opening file", "There was an error opening the log file " + filePath); + // } } } @@ -477,11 +464,7 @@ void SettingsDialog::on_pushButtonSave_clicked() settings.setValue("libDav1dFile", ui.lineEditLibDav1d->text()); settings.setValue("libVTMFile", ui.lineEditLibVTMFile->text()); settings.setValue("libVVDecFile", ui.lineEditLibVVDecFile->text()); - // FFMpeg files - settings.setValue("FFmpeg.avformat", ui.lineEditAVFormat->text()); - settings.setValue("FFmpeg.avcodec", ui.lineEditAVCodec->text()); - settings.setValue("FFmpeg.avutil", ui.lineEditAVUtil->text()); - settings.setValue("FFmpeg.swresample", ui.lineEditSWResample->text()); + settings.setValue("FFmpeg.path", ui.lineEditFFmpegPath->text()); settings.endGroup(); accept(); diff --git a/YUViewLib/src/ui/SettingsDialog.h b/YUViewLib/src/ui/SettingsDialog.h index c19ba3dc1..308898894 100644 --- a/YUViewLib/src/ui/SettingsDialog.h +++ b/YUViewLib/src/ui/SettingsDialog.h @@ -1,34 +1,34 @@ /* This file is part of YUView - The YUV player with advanced analytics toolset -* -* Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 3 of the License, or -* (at your option) any later version. -* -* In addition, as a special exception, the copyright holders give -* permission to link the code of portions of this program with the -* OpenSSL library under certain conditions as described in each -* individual source file, and distribute linked combinations including -* the two. -* -* You must obey the GNU General Public License in all respects for all -* of the code used other than OpenSSL. If you modify file(s) with this -* exception, you may extend this exception to your version of the -* file(s), but you are not obligated to do so. If you do not wish to do -* so, delete this exception statement from your version. If you delete -* this exception statement from all source files in the program, then -* also delete it here. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ + * + * Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations including + * the two. + * + * You must obey the GNU General Public License in all respects for all + * of the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do + * so, delete this exception statement from your version. If you delete + * this exception statement from all source files in the program, then + * also delete it here. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ #pragma once @@ -43,7 +43,7 @@ class SettingsDialog : public QDialog public: explicit SettingsDialog(QWidget *parent = 0); static void initializeDefaults(); - + // Get settings unsigned int getCacheSizeInMB() const; @@ -70,22 +70,19 @@ private slots: void on_pushButtonLibDav1dSelectFile_clicked(); void on_pushButtonLibVTMSelectFile_clicked(); void on_pushButtonLibVVDecSelectFile_clicked(); - void on_pushButtonFFMpegSelectFile_clicked(); + void on_pushButtonFFMpegSelectPath_clicked(); void on_pushButtonDecoderClearPath_clicked() { ui.lineEditDecoderPath->clear(); } void on_pushButtonLibde265ClearFile_clicked() { ui.lineEditLibde265File->clear(); } void on_pushButtonlibHMClearFile_clicked() { ui.lineEditLibHMFile->clear(); } void on_pushButtonLibDav1dClearFile_clicked() { ui.lineEditLibDav1d->clear(); } void on_pushButtonLibVTMClearFile_clicked() { ui.lineEditLibVTMFile->clear(); } void on_pushButtonLibVVDecClearFile_clicked() { ui.lineEditLibVVDecFile->clear(); } - void on_pushButtonFFMpegClearFile_clicked() { ui.lineEditAVFormat->clear(); ui.lineEditAVCodec->clear(); ui.lineEditAVUtil->clear(); ui.lineEditSWResample->clear(); } + void on_pushButtonFFMpegClearPath_clicked() { ui.lineEditFFmpegPath->clear(); } // Save/Load buttons void on_pushButtonSave_clicked(); void on_pushButtonCancel_clicked() { reject(); } private: - // Open a file search dialog and return the selected file (or an empty string if no file was selected) - QStringList getLibraryPath(QString currentFile, QString caption, bool multipleFiles=false); - Ui::SettingsDialog ui; };