diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 9918cf558..1e5805b6e 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -20,6 +20,8 @@ jobs: QMAKE_COMMAND: qmake6 steps: - uses: actions/checkout@v4 + with: + submodules: true - run: git fetch --prune --unshallow - name: Install Linux packages run: | @@ -32,7 +34,8 @@ jobs: cd build ${{matrix.QMAKE_COMMAND}} CONFIG+=UNITTESTS .. make -j$(nproc) - make check + - name: Run Unittests + run: $GITHUB_WORKSPACE/build/YUViewUnitTest/YUViewUnitTest build-mac-native: runs-on: ${{ matrix.os }} strategy: @@ -42,6 +45,8 @@ jobs: - os: macos-14 steps: - uses: actions/checkout@v4 + with: + submodules: true - run: git fetch --prune --unshallow - name: Install packages run: | @@ -53,7 +58,8 @@ jobs: cd build qmake6 CONFIG+=UNITTESTS .. make -j $(sysctl -n hw.logicalcpu) - make check + - name: Run Unittests + run: $GITHUB_WORKSPACE/build/YUViewUnitTest/YUViewUnitTest build-unix: runs-on: ${{ matrix.os }} strategy: @@ -79,6 +85,8 @@ jobs: CPU_COUNT_COMMAND: sysctl -n hw.logicalcpu steps: - uses: actions/checkout@v4 + with: + submodules: true - run: git fetch --prune --unshallow - name: Install Qt base run: | @@ -104,7 +112,7 @@ jobs: curl -L https://github.com/ChristianFeldmann/libde265/releases/download/v1.1/${{matrix.LIBDE265_REMOTE}} -o ${{matrix.LIBDE265_LOCAL}} curl -L https://raw.githubusercontent.com/ChristianFeldmann/libde265/master/COPYING -o libde265License.txt shell: bash - - name: Build Linux/Mac + - name: Build run: | cd $GITHUB_WORKSPACE export PATH=$GITHUB_WORKSPACE/../../YUViewQt/YUViewQt/Qt/bin:$PATH @@ -112,7 +120,8 @@ jobs: cd build qmake CONFIG+=UNITTESTS .. make -j $(${{matrix.CPU_COUNT_COMMAND}}) - make check + - name: Run Unittests + run: $GITHUB_WORKSPACE/build/YUViewUnitTest/YUViewUnitTest - name: Build App (Mac) run: | macdeployqt build/YUViewApp/YUView.app -always-overwrite -verbose=2 @@ -122,7 +131,7 @@ jobs: zip -r ${{matrix.ARTIFACT_NAME}} YUView.app/ mkdir $GITHUB_WORKSPACE/artifacts cp ${{matrix.ARTIFACT_NAME}} $GITHUB_WORKSPACE/artifacts/ - if: matrix.os == 'macos-11' || matrix.os == 'macos-12' + if: matrix.os == 'macos-12' || matrix.os == 'macos-14' - name: Build Appimage (Linux) run: | cd build @@ -157,6 +166,8 @@ jobs: QT_FILE: qtBase_6.7.2_win2019.zip steps: - uses: actions/checkout@v4 + with: + submodules: true - uses: ilammy/msvc-dev-cmd@v1 - run: git fetch --prune --unshallow - name: Install Qt base @@ -196,11 +207,8 @@ jobs: d:\a\YUViewQt\YUViewQt\Qt\bin\qmake CONFIG+=UNITTESTS .. echo "Executing jom:" jom - - name: Run tests - run: | - cd build - nmake check - cd .. + - name: Run Unittests + run: D:\a\YUView\YUView\build\YUViewUnitTest\YUViewUnitTest - name: WindeployQT run: | mkdir deploy diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..71b2104a5 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "submodules/googletest"] + path = submodules/googletest + url = git@github.com:google/googletest.git diff --git a/YUView.pro b/YUView.pro index b34aa2300..8723a880f 100644 --- a/YUView.pro +++ b/YUView.pro @@ -7,7 +7,11 @@ YUViewLib.subdir = YUViewLib YUViewApp.depends = YUViewLib UNITTESTS { + SUBDIRS += Googletest + Googletest.subdir = submodules/googletest-qmake + SUBDIRS += YUViewUnitTest YUViewUnitTest.subdir = YUViewUnitTest + YUViewUnitTest.depends = Googletest YUViewUnitTest.depends = YUViewLib } diff --git a/YUViewLib/src/common/EnumMapper.h b/YUViewLib/src/common/EnumMapper.h index b163bf5a3..bad1e4c19 100644 --- a/YUViewLib/src/common/EnumMapper.h +++ b/YUViewLib/src/common/EnumMapper.h @@ -1,6 +1,6 @@ /* This file is part of YUView - The YUV player with advanced analytics toolset * - * Copyright (C) 2015 Institut f�r Nachrichtentechnik, RWTH Aachen University, GERMANY + * 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 @@ -32,135 +32,166 @@ #pragma once -#include - -#include +#include +#include +#include #include -#include -#include -#include +#include -/* This class implement mapping of "enum class" values to and from names (string). - */ -template class EnumMapper -{ -public: - enum class StringType - { - Name, - Text, - NameOrIndex - }; - struct Entry - { - Entry(T value, std::string name) : value(value), name(name) {} - Entry(T value, std::string name, std::string text) : value(value), name(name), text(text) {} - T value; - std::string name; - std::string text; - }; +#include "Functions.h" - using EntryVector = std::vector; +using namespace std::string_view_literals; - EnumMapper() = default; - EnumMapper(const EntryVector &entryVector) : entryVector(entryVector){}; +template struct EnumMapper +{ +public: + using ValueNamePair = std::pair; + using ItemArray = std::array; + using ItemIterator = typename ItemArray::const_iterator; + using NameArray = std::array; + using NameIterator = typename NameArray::const_iterator; - std::optional getValue(std::string name, StringType stringType = StringType::Name) const + struct Iterator { - if (stringType == StringType::NameOrIndex) - if (auto index = functions::toUnsigned(name)) - return this->at(*index); + using iterator_category = std::forward_iterator_tag; + using difference_type = int; + using value_type = ValueNamePair; + using pointer = ValueNamePair *; + using reference = ValueNamePair &; - for (const auto &entry : this->entryVector) + Iterator(const ItemIterator itItem, const NameIterator itName) : itItem(itItem), itName(itName) { - if ((stringType == StringType::Name && entry.name == name) || - (stringType == StringType::NameOrIndex && entry.text == name) || - (stringType == StringType::Text && entry.text == name)) - return entry.value; + this->valueNamePair.first = *itItem; + this->valueNamePair.second = *itName; } - return {}; - } - std::optional getValueCaseInsensitive(std::string name, - StringType stringType = StringType::Name) const - { - if (stringType == StringType::NameOrIndex) - if (auto index = functions::toUnsigned(name)) - return this->at(*index); + ValueNamePair const &operator*() const { return this->valueNamePair; } + ValueNamePair const *operator->() const { return &this->valueNamePair; } - name = functions::toLower(name); - for (const auto &entry : this->entryVector) + Iterator &operator++() { - if ((stringType == StringType::Name && functions::toLower(entry.name) == name) || - (stringType == StringType::NameOrIndex && functions::toLower(entry.text) == name) || - (stringType == StringType::Text && functions::toLower(entry.text) == name)) - return entry.value; + ++this->itItem; + ++this->itName; + this->valueNamePair.first = *this->itItem; + this->valueNamePair.second = *this->itName; + return *this; } - return {}; - } - std::string getName(T value) const + friend bool operator==(const Iterator &a, const Iterator &b) + { + return a.itItem == b.itItem && a.itName == b.itName; + }; + friend bool operator!=(const Iterator &a, const Iterator &b) + { + return a.itItem != b.itItem || a.itName != b.itName; + }; + + private: + ItemIterator itItem; + NameIterator itName; + ValueNamePair valueNamePair{}; + }; + + Iterator begin() const { return Iterator(this->items.begin(), this->names.begin()); } + Iterator end() const { return Iterator(this->items.end(), this->names.end()); } + + template constexpr EnumMapper(Args... args) { - for (const auto &entry : this->entryVector) - if (entry.value == value) - return entry.name; - throw std::logic_error( - "The given type T was not registered in the mapper. All possible enums must be mapped."); + static_assert(sizeof...(Args) == N); + this->addElementsRecursively(0, args...); } - std::string getText(T value) const + constexpr std::size_t size() const { return N; } + + constexpr std::string_view getName(const ValueType value) const { - for (const auto &entry : this->entryVector) - if (entry.value == value) - return entry.text; - throw std::logic_error( - "The given type T was not registered in the mapper. All possible enums must be mapped."); + const auto it = std::find(this->items.begin(), this->items.end(), value); + if (it == this->items.end()) + throw std::logic_error( + "The given type T was not registered in the mapper. All possible enums must be mapped."); + const auto index = std::distance(this->items.begin(), it); + return this->names.at(index); } - size_t indexOf(T value) const + constexpr std::optional getValue(const std::string_view name) const { - for (size_t i = 0; i < this->entryVector.size(); i++) - if (this->entryVector.at(i).value == value) - return i; - throw std::logic_error( - "The given type T was not registered in the mapper. All possible enums must be mapped."); + const auto it = + std::find_if(this->begin(), + this->end(), + [&name](const ValueNamePair &pair) { return pair.second == name; }); + if (it == this->end()) + return {}; + + return it->first; } - std::optional at(size_t index) const + constexpr std::optional getValueCaseInsensitive(const std::string_view name) const { - if (index >= this->entryVector.size()) + const auto compareToNameLowercase = [&name](const std::string_view str) + { + if (name.length() != str.length()) + return false; + for (std::size_t i = 0; i < name.length(); ++i) + { + if (std::tolower(name.at(i)) != std::tolower(str.at(i))) + return false; + } + return true; + }; + + const auto it = std::find_if(this->names.begin(), this->names.end(), compareToNameLowercase); + if (it == this->names.end()) return {}; - return this->entryVector.at(index).value; + + const auto index = std::distance(this->names.begin(), it); + return this->items.at(index); } - std::vector getEnums() const + std::optional getValueFromNameOrIndex(const std::string_view nameOrIndex) const { - std::vector m; - for (const auto &entry : this->entryVector) - m.push_back(entry.value); - return m; + if (auto index = functions::toUnsigned(nameOrIndex)) + if (*index < N) + return this->items.at(*index); + + return this->getValue(nameOrIndex); } - std::vector getNames() const + constexpr size_t indexOf(const ValueType value) const { - std::vector l; - for (const auto &entry : this->entryVector) - l.push_back(entry.name); - return l; + const auto it = std::find(this->items.begin(), this->items.end(), value); + if (it == this->items.end()) + throw std::logic_error( + "The given type T was not registered in the mapper. All possible enums must be mapped."); + + const auto index = std::distance(this->items.begin(), it); + return index; } - std::vector getTextEntries() const + constexpr std::optional at(const size_t index) const { - std::vector l; - for (const auto &entry : this->entryVector) - l.push_back(entry.text); - return l; + if (index >= N) + return {}; + return this->items.at(index); } - size_t size() const { return this->entryVector.size(); } - - const EntryVector &entries() const { return this->entryVector; } + constexpr const ItemArray &getValues() const { return this->items; } + constexpr const NameArray &getNames() const { return this->names; } private: - EntryVector entryVector; + constexpr void addElementsRecursively(const std::size_t) {}; + + template + constexpr void addElementsRecursively(const std::size_t index, ArgumentType first, Args... args) + { + static_assert(std::is_same()); + + const auto [value, name] = first; + this->items[index] = value; + this->names[index] = name; + + addElementsRecursively(index + 1, args...); + } + + ItemArray items{}; + NameArray names{}; }; diff --git a/YUViewLib/src/common/Formatting.h b/YUViewLib/src/common/Formatting.h index 6681978e1..427014c2d 100644 --- a/YUViewLib/src/common/Formatting.h +++ b/YUViewLib/src/common/Formatting.h @@ -77,9 +77,31 @@ static std::ostream &operator<<(std::ostream &stream, const Size &size) return stream; } -static std::string to_string(const Size &size) +inline std::string to_string(const Size &size) { std::ostringstream stream; stream << size; return stream.str(); } + +inline std::string to_string(const bool b) +{ + return b ? "True" : "False"; +} + +inline std::string stringReplaceAll(std::string str, char value, char replacement) +{ + std::replace(str.begin(), str.end(), value, replacement); + return str; +} + +inline std::string stringReplaceAll(std::string str, std::initializer_list values, char replacement) +{ + std::replace_if( + str.begin(), + str.end(), + [&values](const char value) + { return std::find(values.begin(), values.end(), value) != values.end(); }, + replacement); + return str; +} diff --git a/YUViewLib/src/common/Functions.cpp b/YUViewLib/src/common/Functions.cpp index ce6d6ebdf..47ce90f0c 100644 --- a/YUViewLib/src/common/Functions.cpp +++ b/YUViewLib/src/common/Functions.cpp @@ -42,6 +42,8 @@ #endif #include +#include +#include #include @@ -161,11 +163,14 @@ QStringList toQStringList(const std::vector &stringVec) return list; } -std::string toLower(std::string str) +std::string toLower(const std::string_view str) { - std::transform( - str.begin(), str.end(), str.begin(), [](unsigned char c) { return std::tolower(c); }); - return str; + std::string lowercaseStr(str); + std::transform(lowercaseStr.begin(), + lowercaseStr.end(), + lowercaseStr.begin(), + [](unsigned char c) { return std::tolower(c); }); + return lowercaseStr; } ByteVector readData(std::istream &istream, const size_t nrBytes) @@ -178,17 +183,18 @@ ByteVector readData(std::istream &istream, const size_t nrBytes) return data; } -std::optional toUnsigned(const std::string &text) +std::optional toUnsigned(const std::string_view text) { - try - { - auto index = std::stoul(text); - return index; - } - catch (...) - { + int value{}; + const auto result = std::from_chars(text.data(), text.data() + text.size(), value); + + if (result.ec != std::errc()) return {}; - } + const auto allCharactersParsed = (result.ptr == &(*text.end())); + if (!allCharactersParsed) + return {}; + + return value; } } // namespace functions diff --git a/YUViewLib/src/common/Functions.h b/YUViewLib/src/common/Functions.h index a06553ea6..33a115d6a 100644 --- a/YUViewLib/src/common/Functions.h +++ b/YUViewLib/src/common/Functions.h @@ -64,14 +64,19 @@ QStringList getThemeColors(QString themeName); QString formatDataSize(double size, bool isBits = false); QStringList toQStringList(const std::vector &stringVec); -std::string toLower(std::string str); -ByteVector readData(std::istream &istream, const size_t nrBytes); -inline std::string boolToString(bool b) +template +QStringList toQStringList(const std::array &stringArray) { - return b ? "True" : "False"; + QStringList list; + for (const auto &s : stringArray) + list.append(QString::fromStdString(std::string(s))); + return list; } +std::string toLower(const std::string_view str); +ByteVector readData(std::istream &istream, const size_t nrBytes); + template unsigned clipToUnsigned(T val) { static_assert(std::is_signed::value, "T must must be a signed type"); @@ -90,6 +95,6 @@ template inline T clip(T val, Range range) return (val < T(range.min)) ? T(range.min) : (val > T(range.max)) ? T(range.max) : val; } -std::optional toUnsigned(const std::string &text); +std::optional toUnsigned(const std::string_view text); } // namespace functions diff --git a/YUViewLib/src/common/YUViewDomElement.cpp b/YUViewLib/src/common/YUViewDomElement.cpp index 8b407ede8..b99965d19 100644 --- a/YUViewLib/src/common/YUViewDomElement.cpp +++ b/YUViewLib/src/common/YUViewDomElement.cpp @@ -76,8 +76,8 @@ double YUViewDomElement::findChildValueDouble(const QString &tagName, double def return r.isEmpty() ? defaultValue : r.toDouble(); }; -void YUViewDomElement::appendProperiteChild(const QString & type, - const QString & name, +void YUViewDomElement::appendProperiteChild(const QString &type, + const QString &name, const QStringPairList &attributes) { auto newChild = ownerDocument().createElement(type); @@ -87,14 +87,16 @@ void YUViewDomElement::appendProperiteChild(const QString & type, appendChild(newChild); } -void YUViewDomElement::setAttribute(const std::string &name, const std::string &value) +void YUViewDomElement::setAttribute(const std::string_view name, const std::string_view value) { - QDomElement::setAttribute(QString::fromStdString(name), QString::fromStdString(value)); + QDomElement::setAttribute(QString::fromStdString(std::string(name)), + QString::fromStdString(std::string(value))); } -void YUViewDomElement::appendProperiteChild(const std::string &type, const std::string &name) +void YUViewDomElement::appendProperiteChild(const std::string_view type, + const std::string_view name) { - auto newChild = ownerDocument().createElement(QString::fromStdString(type)); - newChild.appendChild(ownerDocument().createTextNode(QString::fromStdString(name))); + auto newChild = ownerDocument().createElement(QString::fromStdString(std::string(type))); + newChild.appendChild(ownerDocument().createTextNode(QString::fromStdString(std::string(name)))); appendChild(newChild); } diff --git a/YUViewLib/src/common/YUViewDomElement.h b/YUViewLib/src/common/YUViewDomElement.h index 8964ed285..03b08aa64 100644 --- a/YUViewLib/src/common/YUViewDomElement.h +++ b/YUViewLib/src/common/YUViewDomElement.h @@ -52,10 +52,10 @@ class YUViewDomElement : public QDomElement double findChildValueDouble(const QString &tagName, double defaultValue) const; using QDomElement::setAttribute; - void setAttribute(const std::string &name, const std::string &value); + void setAttribute(const std::string_view name, const std::string_view value); - void appendProperiteChild(const QString & type, - const QString & name, + void appendProperiteChild(const QString &type, + const QString &name, const QStringPairList &attributes = QStringPairList()); - void appendProperiteChild(const std::string &type, const std::string &name); + void appendProperiteChild(const std::string_view type, const std::string_view name); }; diff --git a/YUViewLib/src/decoder/decoderBase.h b/YUViewLib/src/decoder/decoderBase.h index 1b5c18ae1..0134a8588 100644 --- a/YUViewLib/src/decoder/decoderBase.h +++ b/YUViewLib/src/decoder/decoderBase.h @@ -64,13 +64,14 @@ enum class DecoderEngine FFMpeg // The FFMpeg decoder }; -const auto DecoderEngineMapper = EnumMapper({{DecoderEngine::Invalid, "Invalid"}, - {DecoderEngine::Libde265, "Libde265"}, - {DecoderEngine::HM, "HM"}, - {DecoderEngine::VTM, "VTM"}, - {DecoderEngine::VVDec, "VVDec"}, - {DecoderEngine::Dav1d, "Dav1d"}, - {DecoderEngine::FFMpeg, "FFMpeg"}}); +constexpr EnumMapper + DecoderEngineMapper(std::make_pair(DecoderEngine::Invalid, "Invalid"sv), + std::make_pair(DecoderEngine::Libde265, "Libde265"sv), + std::make_pair(DecoderEngine::HM, "HM"sv), + std::make_pair(DecoderEngine::VTM, "VTM"sv), + std::make_pair(DecoderEngine::VVDec, "VVDec"sv), + std::make_pair(DecoderEngine::Dav1d, "Dav1d"sv), + std::make_pair(DecoderEngine::FFMpeg, "FFMpeg"sv)); const auto DecodersHEVC = std::vector({DecoderEngine::Libde265, DecoderEngine::HM, DecoderEngine::FFMpeg}); @@ -90,7 +91,7 @@ class decoderBase // Create a new decoder. cachingDecoder: Is this a decoder used for caching or interactive // decoding? decoderBase(bool cachingDecoder = false); - virtual ~decoderBase(){}; + virtual ~decoderBase() {}; // Reset the decoder. Afterwards, the decoder should behave as if you just created a new one // (without the overhead of reloading the libraries). This must be used in case of errors or when @@ -179,8 +180,8 @@ class decoderBase class decoderBaseSingleLib : public decoderBase { public: - decoderBaseSingleLib(bool cachingDecoder = false) : decoderBase(cachingDecoder){}; - virtual ~decoderBaseSingleLib(){}; + decoderBaseSingleLib(bool cachingDecoder = false) : decoderBase(cachingDecoder) {}; + virtual ~decoderBaseSingleLib() {}; QStringList getLibraryPaths() const override { diff --git a/YUViewLib/src/decoder/decoderTarga.cpp b/YUViewLib/src/decoder/decoderTarga.cpp index 1e44260ae..2560fbae7 100644 --- a/YUViewLib/src/decoder/decoderTarga.cpp +++ b/YUViewLib/src/decoder/decoderTarga.cpp @@ -35,8 +35,6 @@ #include "decoderTarga.h" -#include - #include #include diff --git a/YUViewLib/src/filesource/FileSource.cpp b/YUViewLib/src/filesource/FileSource.cpp index 7e5daf3de..336d9d1c8 100644 --- a/YUViewLib/src/filesource/FileSource.cpp +++ b/YUViewLib/src/filesource/FileSource.cpp @@ -36,7 +36,6 @@ #include #include -#include #include #include #ifdef Q_OS_WIN @@ -142,166 +141,6 @@ QString FileSource::getAbsoluteFilePath() const return this->isFileOpened ? this->fileInfo.absoluteFilePath() : QString(); } -FileSource::fileFormat_t FileSource::guessFormatFromFilename() const -{ - FileSource::fileFormat_t format; - - // We are going to check two strings (one after the other) for indicators on the frames size, fps - // and bit depth. 1: The file name, 2: The folder name that the file is contained in. - - auto dirName = this->fileInfo.absoluteDir().dirName(); - auto fileName = this->fileInfo.fileName(); - if (fileName.isEmpty()) - return format; - - for (auto const &name : {fileName, dirName}) - { - // First, we will try to get a frame size from the name - if (!format.frameSize.isValid()) - { - // The regular expressions to match. They are sorted from most detailed to least so that the - // most detailed ones are tested first. - auto regExprList = - QStringList() - << "([0-9]+)(?:x|X|\\*)([0-9]+)_([0-9]+)(?:Hz)?_([0-9]+)b?[\\._]" // Something_2160x1440_60_8_more.yuv - // or - // Something_2160x1440_60_8b.yuv - // or - // Something_2160x1440_60Hz_8_more.yuv - << "([0-9]+)(?:x|X|\\*)([0-9]+)_([0-9]+)(?:Hz)?[\\._]" // Something_2160x1440_60_more.yuv - // or Something_2160x1440_60.yuv - << "([0-9]+)(?:x|X|\\*)([0-9]+)[\\._]"; // Something_2160x1440_more.yuv or - // Something_2160x1440.yuv - - for (auto regExpStr : regExprList) - { - QRegularExpression exp(regExpStr); - auto match = exp.match(name); - if (match.hasMatch()) - { - auto widthString = match.captured(1); - auto heightString = match.captured(2); - format.frameSize = Size(widthString.toInt(), heightString.toInt()); - - auto rateString = match.captured(3); - if (!rateString.isEmpty()) - format.frameRate = rateString.toDouble(); - - auto bitDepthString = match.captured(4); - if (!bitDepthString.isEmpty()) - format.bitDepth = bitDepthString.toUInt(); - - break; // Don't check the following expressions - } - } - } - - // try resolution indicators with framerate: "1080p50", "720p24" ... - if (!format.frameSize.isValid()) - { - QRegularExpression rx1080p("1080p([0-9]+)"); - auto matchIt = rx1080p.globalMatch(name); - if (matchIt.hasNext()) - { - auto match = matchIt.next(); - format.frameSize = Size(1920, 1080); - auto frameRateString = match.captured(1); - format.frameRate = frameRateString.toInt(); - } - } - if (!format.frameSize.isValid()) - { - QRegularExpression rx720p("720p([0-9]+)"); - auto matchIt = rx720p.globalMatch(name); - if (matchIt.hasNext()) - { - auto match = matchIt.next(); - format.frameSize = Size(1280, 720); - auto frameRateString = match.captured(1); - format.frameRate = frameRateString.toInt(); - } - } - - if (!format.frameSize.isValid()) - { - // try to find resolution indicators (e.g. 'cif', 'hd') in file name - if (name.contains("_cif", Qt::CaseInsensitive)) - format.frameSize = Size(352, 288); - else if (name.contains("_qcif", Qt::CaseInsensitive)) - format.frameSize = Size(176, 144); - else if (name.contains("_4cif", Qt::CaseInsensitive)) - format.frameSize = Size(704, 576); - else if (name.contains("UHD", Qt::CaseSensitive)) - format.frameSize = Size(3840, 2160); - else if (name.contains("HD", Qt::CaseSensitive)) - format.frameSize = Size(1920, 1080); - else if (name.contains("1080p", Qt::CaseSensitive)) - format.frameSize = Size(1920, 1080); - else if (name.contains("720p", Qt::CaseSensitive)) - format.frameSize = Size(1280, 720); - } - - // Second, if we were able to get a frame size but no frame rate, we will try to get a frame - // rate. - if (format.frameSize.isValid() && format.frameRate == -1) - { - // Look for: 24fps, 50fps, 24FPS, 50FPS - QRegularExpression rxFPS("([0-9]+)fps", QRegularExpression::CaseInsensitiveOption); - auto match = rxFPS.match(name); - if (match.hasMatch()) - { - auto frameRateString = match.captured(1); - format.frameRate = frameRateString.toInt(); - } - } - if (format.frameSize.isValid() && format.frameRate == -1) - { - // Look for: 24Hz, 50Hz, 24HZ, 50HZ - QRegularExpression rxHZ("([0-9]+)HZ", QRegularExpression::CaseInsensitiveOption); - auto match = rxHZ.match(name); - if (match.hasMatch()) - { - QString frameRateString = match.captured(1); - format.frameRate = frameRateString.toInt(); - } - } - - // Third, if we were able to get a frame size but no bit depth, we try to get a bit depth. - if (format.frameSize.isValid() && format.bitDepth == 0) - { - for (unsigned bd : {8, 9, 10, 12, 16}) - { - // Look for: 10bit, 10BIT, 10-bit, 10-BIT - if (name.contains(QString("%1bit").arg(bd), Qt::CaseInsensitive) || - name.contains(QString("%1-bit").arg(bd), Qt::CaseInsensitive)) - { - format.bitDepth = bd; - break; - } - // Look for bit depths like: _16b_ .8b. -12b- - QRegularExpression exp(QString("(?:_|\\.|-)%1b(?:_|\\.|-)").arg(bd)); - auto match = exp.match(name); - if (match.hasMatch()) - { - format.bitDepth = bd; - break; - } - } - } - - // If we were able to get a frame size, try to get an indicator for packed formats - if (format.frameSize.isValid()) - { - QRegularExpression exp("(?:_|\\.|-)packed(?:_|\\.|-)"); - auto match = exp.match(name); - if (match.hasMatch()) - format.packed = true; - } - } - - return format; -} - // If you are loading a playlist and you have an absolute path and a relative path, this function // will return the absolute path (if a file with that absolute path exists) or convert the relative // path to an absolute one and return that (if that file exists). If neither exists the empty string diff --git a/YUViewLib/src/filesource/FileSource.h b/YUViewLib/src/filesource/FileSource.h index 6aa3f19c0..c6057b512 100644 --- a/YUViewLib/src/filesource/FileSource.h +++ b/YUViewLib/src/filesource/FileSource.h @@ -39,8 +39,8 @@ #include #include -#include #include +#include #include enum class InputFormat @@ -52,11 +52,12 @@ enum class InputFormat Libav // This is some sort of container file which we will read using libavformat }; -const auto InputFormatMapper = EnumMapper({{InputFormat::Invalid, "Invalid"}, - {InputFormat::AnnexBHEVC, "AnnexBHEVC"}, - {InputFormat::AnnexBAVC, "AnnexBAVC"}, - {InputFormat::AnnexBVVC, "AnnexBVVC"}, - {InputFormat::Libav, "Libav"}}); +constexpr EnumMapper + InputFormatMapper(std::make_pair(InputFormat::Invalid, "Invalid"sv), + std::make_pair(InputFormat::AnnexBHEVC, "AnnexBHEVC"sv), + std::make_pair(InputFormat::AnnexBAVC, "AnnexBAVC"sv), + std::make_pair(InputFormat::AnnexBVVC, "AnnexBVVC"sv), + std::make_pair(InputFormat::Libav, "Libav"sv)); /* The FileSource class provides functions for accessing files. Besides the reading of * certain blocks of the file, it also directly provides information on the file for the @@ -75,7 +76,7 @@ class FileSource : public QObject int64_t getFileSize() const { return !isFileOpened ? -1 : fileInfo.size(); } QString getAbsoluteFilePath() const; QFileInfo getFileInfo() const { return this->fileInfo; } - QFile * getQFile() { return &this->srcFile; } + QFile *getQFile() { return &this->srcFile; } bool getAndResetFileChangedFlag(); // Return true if the file could be opened and is ready for use. @@ -86,15 +87,6 @@ class FileSource : public QObject virtual bool seek(int64_t pos) { return !this->isFileOpened ? false : this->srcFile.seek(pos); } int64_t pos() { return !this->isFileOpened ? 0 : this->srcFile.pos(); } - struct fileFormat_t - { - Size frameSize; - int frameRate{-1}; - unsigned bitDepth{}; - bool packed{false}; - }; - fileFormat_t guessFormatFromFilename() const; - // Get the file size in bytes // Read the given number of bytes starting at startPos into the QByteArray out diff --git a/YUViewLib/src/filesource/GuessFormatFromName.cpp b/YUViewLib/src/filesource/GuessFormatFromName.cpp new file mode 100644 index 000000000..c0cc9712c --- /dev/null +++ b/YUViewLib/src/filesource/GuessFormatFromName.cpp @@ -0,0 +1,204 @@ +/* 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 . + */ + +#include "GuessFormatFromName.h" + +#include +#include + +bool FileFormat::operator== (const FileFormat &rhs) const +{ + return this->frameSize == rhs.frameSize && // + this->frameRate == rhs.frameRate && // + this->bitDepth == rhs.bitDepth && // + this->packed == rhs.packed; +} + +FileFormat guessFormatFromFilename(const QFileInfo &fileInfo) +{ + FileFormat format; + + // We are going to check two strings (one after the other) for indicators on the frames size, fps + // and bit depth. 1: The file name, 2: The folder name that the file is contained in. + + const auto dirName = fileInfo.absoluteDir().dirName(); + const auto fileName = fileInfo.fileName(); + if (fileName.isEmpty()) + return format; + + for (auto const &name : {fileName, dirName}) + { + // First, we will try to get a frame size from the name + if (!format.frameSize.isValid()) + { + // The regular expressions to match. They are sorted from most detailed to least so that the + // most detailed ones are tested first. + auto regExprList = + QStringList() + << "([0-9]+)(?:x|X|\\*)([0-9]+)_([0-9]+)(?:Hz)?_([0-9]+)b?[\\._]" // Something_2160x1440_60_8_more.yuv + // or + // Something_2160x1440_60_8b.yuv + // or + // Something_2160x1440_60Hz_8_more.yuv + << "([0-9]+)(?:x|X|\\*)([0-9]+)_([0-9]+)(?:Hz)?[\\._]" // Something_2160x1440_60_more.yuv + // or Something_2160x1440_60.yuv + << "([0-9]+)(?:x|X|\\*)([0-9]+)[\\._]"; // Something_2160x1440_more.yuv or + // Something_2160x1440.yuv + + for (auto regExpStr : regExprList) + { + QRegularExpression exp(regExpStr); + auto match = exp.match(name); + if (match.hasMatch()) + { + auto widthString = match.captured(1); + auto heightString = match.captured(2); + format.frameSize = Size(widthString.toInt(), heightString.toInt()); + + auto rateString = match.captured(3); + if (!rateString.isEmpty()) + format.frameRate = rateString.toDouble(); + + auto bitDepthString = match.captured(4); + if (!bitDepthString.isEmpty()) + format.bitDepth = bitDepthString.toUInt(); + + break; // Don't check the following expressions + } + } + } + + // try resolution indicators with framerate: "1080p50", "720p24" ... + if (!format.frameSize.isValid()) + { + QRegularExpression rx1080p("1080p([0-9]+)"); + auto matchIt = rx1080p.globalMatch(name); + if (matchIt.hasNext()) + { + auto match = matchIt.next(); + format.frameSize = Size(1920, 1080); + auto frameRateString = match.captured(1); + format.frameRate = frameRateString.toInt(); + } + } + if (!format.frameSize.isValid()) + { + QRegularExpression rx720p("720p([0-9]+)"); + auto matchIt = rx720p.globalMatch(name); + if (matchIt.hasNext()) + { + auto match = matchIt.next(); + format.frameSize = Size(1280, 720); + auto frameRateString = match.captured(1); + format.frameRate = frameRateString.toInt(); + } + } + + if (!format.frameSize.isValid()) + { + // try to find resolution indicators (e.g. 'cif', 'hd') in file name + if (name.contains("_cif", Qt::CaseInsensitive)) + format.frameSize = Size(352, 288); + else if (name.contains("_qcif", Qt::CaseInsensitive)) + format.frameSize = Size(176, 144); + else if (name.contains("_4cif", Qt::CaseInsensitive)) + format.frameSize = Size(704, 576); + else if (name.contains("UHD", Qt::CaseSensitive)) + format.frameSize = Size(3840, 2160); + else if (name.contains("HD", Qt::CaseSensitive)) + format.frameSize = Size(1920, 1080); + else if (name.contains("1080p", Qt::CaseSensitive)) + format.frameSize = Size(1920, 1080); + else if (name.contains("720p", Qt::CaseSensitive)) + format.frameSize = Size(1280, 720); + } + + // Second, if we were able to get a frame size but no frame rate, we will try to get a frame + // rate. + if (format.frameSize.isValid() && format.frameRate == -1) + { + // Look for: 24fps, 50fps, 24FPS, 50FPS + QRegularExpression rxFPS("([0-9]+)fps", QRegularExpression::CaseInsensitiveOption); + auto match = rxFPS.match(name); + if (match.hasMatch()) + { + auto frameRateString = match.captured(1); + format.frameRate = frameRateString.toInt(); + } + } + if (format.frameSize.isValid() && format.frameRate == -1) + { + // Look for: 24Hz, 50Hz, 24HZ, 50HZ + QRegularExpression rxHZ("([0-9]+)HZ", QRegularExpression::CaseInsensitiveOption); + auto match = rxHZ.match(name); + if (match.hasMatch()) + { + QString frameRateString = match.captured(1); + format.frameRate = frameRateString.toInt(); + } + } + + // Third, if we were able to get a frame size but no bit depth, we try to get a bit depth. + if (format.frameSize.isValid() && format.bitDepth == 0) + { + for (unsigned bd : {8, 9, 10, 12, 16}) + { + // Look for: 10bit, 10BIT, 10-bit, 10-BIT + if (name.contains(QString("%1bit").arg(bd), Qt::CaseInsensitive) || + name.contains(QString("%1-bit").arg(bd), Qt::CaseInsensitive)) + { + format.bitDepth = bd; + break; + } + // Look for bit depths like: _16b_ .8b. -12b- + QRegularExpression exp(QString("(?:_|\\.|-)%1b(?:_|\\.|-)").arg(bd)); + auto match = exp.match(name); + if (match.hasMatch()) + { + format.bitDepth = bd; + break; + } + } + } + + // If we were able to get a frame size, try to get an indicator for packed formats + if (format.frameSize.isValid()) + { + QRegularExpression exp("(?:_|\\.|-)packed(?:_|\\.|-)"); + auto match = exp.match(name); + if (match.hasMatch()) + format.packed = true; + } + } + + return format; +} diff --git a/YUViewLib/src/common/TemporaryFile.cpp b/YUViewLib/src/filesource/GuessFormatFromName.h similarity index 81% rename from YUViewLib/src/common/TemporaryFile.cpp rename to YUViewLib/src/filesource/GuessFormatFromName.h index cd8e364e2..4c216e8ba 100644 --- a/YUViewLib/src/common/TemporaryFile.cpp +++ b/YUViewLib/src/filesource/GuessFormatFromName.h @@ -30,22 +30,20 @@ * along with this program. If not, see . */ -#include "TemporaryFile.h" +#pragma once -std::atomic_uint TemporaryFile::fileCounter{0}; +#include -TemporaryFile::TemporaryFile(std::string extension) -{ - this->filename = "TmpFile" + std::to_string(this->fileCounter.load()) + "." + extension; - this->fileCounter++; -} +#include -TemporaryFile::~TemporaryFile() +struct FileFormat { - std::remove(this->filename.c_str()); -} + Size frameSize; + int frameRate{-1}; + unsigned bitDepth{}; + bool packed{false}; -std::string TemporaryFile::getFilename() const -{ - return this->filename; -} + bool operator==(const FileFormat &rhs) const; +}; + +FileFormat guessFormatFromFilename(const QFileInfo &fileInfo); diff --git a/YUViewLib/src/parser/AVC/nal_unit_header.h b/YUViewLib/src/parser/AVC/nal_unit_header.h index cb8edc91b..32bce2952 100644 --- a/YUViewLib/src/parser/AVC/nal_unit_header.h +++ b/YUViewLib/src/parser/AVC/nal_unit_header.h @@ -32,8 +32,8 @@ #pragma once -#include "common/EnumMapper.h" -#include "parser/common/SubByteReaderLogging.h" +#include +#include namespace parser::avc { @@ -67,31 +67,31 @@ enum class NalType RESERVED_23 }; -const EnumMapper - NalTypeMapper({{NalType::UNSPECIFIED, "UNSPECIFIED"}, - {NalType::CODED_SLICE_NON_IDR, "CODED_SLICE_NON_IDR"}, - {NalType::CODED_SLICE_DATA_PARTITION_A, "CODED_SLICE_DATA_PARTITION_A"}, - {NalType::CODED_SLICE_DATA_PARTITION_B, "CODED_SLICE_DATA_PARTITION_B"}, - {NalType::CODED_SLICE_DATA_PARTITION_C, "CODED_SLICE_DATA_PARTITION_C"}, - {NalType::CODED_SLICE_IDR, "CODED_SLICE_IDR"}, - {NalType::SEI, "SEI"}, - {NalType::SPS, "SPS"}, - {NalType::PPS, "PPS"}, - {NalType::AUD, "AUD"}, - {NalType::END_OF_SEQUENCE, "END_OF_SEQUENCE"}, - {NalType::END_OF_STREAM, "END_OF_STREAM"}, - {NalType::FILLER, "FILLER"}, - {NalType::SPS_EXT, "SPS_EXT"}, - {NalType::PREFIX_NAL, "PREFIX_NAL"}, - {NalType::SUBSET_SPS, "SUBSET_SPS"}, - {NalType::DEPTH_PARAMETER_SET, "DEPTH_PARAMETER_SET"}, - {NalType::RESERVED_17, "RESERVED_17"}, - {NalType::RESERVED_18, "RESERVED_18"}, - {NalType::CODED_SLICE_AUX, "CODED_SLICE_AUX"}, - {NalType::CODED_SLICE_EXTENSION, "CODED_SLICE_EXTENSION"}, - {NalType::CODED_SLICE_EXTENSION_DEPTH_MAP, "CODED_SLICE_EXTENSION_DEPTH_MAP"}, - {NalType::RESERVED_22, "RESERVED_22"}, - {NalType::RESERVED_23, "RESERVED_23"}}); +constexpr EnumMapper NalTypeMapper( + std::make_pair(NalType::UNSPECIFIED, "UNSPECIFIED"sv), + std::make_pair(NalType::CODED_SLICE_NON_IDR, "CODED_SLICE_NON_IDR"sv), + std::make_pair(NalType::CODED_SLICE_DATA_PARTITION_A, "CODED_SLICE_DATA_PARTITION_A"sv), + std::make_pair(NalType::CODED_SLICE_DATA_PARTITION_B, "CODED_SLICE_DATA_PARTITION_B"sv), + std::make_pair(NalType::CODED_SLICE_DATA_PARTITION_C, "CODED_SLICE_DATA_PARTITION_C"sv), + std::make_pair(NalType::CODED_SLICE_IDR, "CODED_SLICE_IDR"sv), + std::make_pair(NalType::SEI, "SEI"sv), + std::make_pair(NalType::SPS, "SPS"sv), + std::make_pair(NalType::PPS, "PPS"sv), + std::make_pair(NalType::AUD, "AUD"sv), + std::make_pair(NalType::END_OF_SEQUENCE, "END_OF_SEQUENCE"sv), + std::make_pair(NalType::END_OF_STREAM, "END_OF_STREAM"sv), + std::make_pair(NalType::FILLER, "FILLER"sv), + std::make_pair(NalType::SPS_EXT, "SPS_EXT"sv), + std::make_pair(NalType::PREFIX_NAL, "PREFIX_NAL"sv), + std::make_pair(NalType::SUBSET_SPS, "SUBSET_SPS"sv), + std::make_pair(NalType::DEPTH_PARAMETER_SET, "DEPTH_PARAMETER_SET"sv), + std::make_pair(NalType::RESERVED_17, "RESERVED_17"sv), + std::make_pair(NalType::RESERVED_18, "RESERVED_18"sv), + std::make_pair(NalType::CODED_SLICE_AUX, "CODED_SLICE_AUX"sv), + std::make_pair(NalType::CODED_SLICE_EXTENSION, "CODED_SLICE_EXTENSION"sv), + std::make_pair(NalType::CODED_SLICE_EXTENSION_DEPTH_MAP, "CODED_SLICE_EXTENSION_DEPTH_MAP"sv), + std::make_pair(NalType::RESERVED_22, "RESERVED_22"sv), + std::make_pair(NalType::RESERVED_23, "RESERVED_23"sv)); class nal_unit_header { diff --git a/YUViewLib/src/parser/HEVC/ParserAnnexBHEVC.cpp b/YUViewLib/src/parser/HEVC/ParserAnnexBHEVC.cpp index a565f7590..390d85a05 100644 --- a/YUViewLib/src/parser/HEVC/ParserAnnexBHEVC.cpp +++ b/YUViewLib/src/parser/HEVC/ParserAnnexBHEVC.cpp @@ -34,6 +34,7 @@ #include #include +#include #include "SEI/buffering_period.h" #include "SEI/pic_timing.h" @@ -285,7 +286,7 @@ Ratio ParserAnnexBHEVC::getSampleAspectRatio() ParserAnnexB::ParseResult ParserAnnexBHEVC::parseAndAddNALUnit(int nalID, - const ByteVector & data, + const ByteVector &data, std::optional bitrateEntry, std::optional nalStartEndPosFile, std::shared_ptr parent) @@ -331,8 +332,8 @@ ParserAnnexBHEVC::parseAndAddNALUnit(int reader::SubByteReaderLogging reader(data, nalRoot, "", getStartCodeOffset(data)); - std::string specificDescription; - auto nalHEVC = std::make_shared(nalID, nalStartEndPosFile); + std::stringstream specificDescription; + auto nalHEVC = std::make_shared(nalID, nalStartEndPosFile); bool first_slice_segment_in_pic_flag = false; bool currentSliceIntra = false; @@ -340,7 +341,7 @@ ParserAnnexBHEVC::parseAndAddNALUnit(int try { nalHEVC->header.parse(reader); - specificDescription = " " + NalTypeMapper.getName(nalHEVC->header.nal_unit_type); + specificDescription << " " << NalTypeMapper.getName(nalHEVC->header.nal_unit_type); if (nalHEVC->header.nal_unit_type == NalType::VPS_NUT) { @@ -349,7 +350,7 @@ ParserAnnexBHEVC::parseAndAddNALUnit(int this->activeParameterSets.vpsMap[newVPS->vps_video_parameter_set_id] = newVPS; - specificDescription += " ID " + std::to_string(newVPS->vps_video_parameter_set_id); + specificDescription << " ID " << newVPS->vps_video_parameter_set_id; nalHEVC->rbsp = newVPS; nalHEVC->rawData = data; @@ -366,7 +367,7 @@ ParserAnnexBHEVC::parseAndAddNALUnit(int this->activeParameterSets.spsMap[newSPS->sps_seq_parameter_set_id] = newSPS; - specificDescription += " ID " + std::to_string(newSPS->sps_seq_parameter_set_id); + specificDescription << " ID " << newSPS->sps_seq_parameter_set_id; DEBUG_HEVC("ParserAnnexBHEVC::parseAndAddNALUnit Parse SPS ID " << newSPS->sps_seq_parameter_set_id); @@ -383,7 +384,7 @@ ParserAnnexBHEVC::parseAndAddNALUnit(int this->activeParameterSets.ppsMap[newPPS->pps_pic_parameter_set_id] = newPPS; - specificDescription += " ID " + std::to_string(newPPS->pps_pic_parameter_set_id); + specificDescription << " ID " << newPPS->pps_pic_parameter_set_id; DEBUG_HEVC("ParserAnnexBHEVC::parseAndAddNALUnit Parse SPS ID " << newPPS->pps_pic_parameter_set_id); @@ -515,7 +516,7 @@ ParserAnnexBHEVC::parseAndAddNALUnit(int currentSliceType = to_string(newSlice->sliceSegmentHeader.slice_type); const auto pocDetail = formatNalPOCDetail(poc, nalHEVC->header.nuh_layer_id); - specificDescription += pocDetail; + specificDescription << pocDetail; parseResult.nalTypeName = "Slice" + pocDetail; DEBUG_HEVC("ParserAnnexBHEVC::parseAndAddNALUnit Slice POC " @@ -535,7 +536,7 @@ ParserAnnexBHEVC::parseAndAddNALUnit(int for (const auto &sei : newSEI->seis) { - specificDescription += " " + sei.getPayloadTypeName(); + specificDescription << " " << sei.getPayloadTypeName(); if (sei.payloadType == 0) { @@ -577,7 +578,7 @@ ParserAnnexBHEVC::parseAndAddNALUnit(int // Technically this is not a specific NAL unit type but dolby vision uses a different // seperator that makes the DV metadata and EL data appear to be NAL unit type 62 and 63. // https://patents.google.com/patent/US20180278963A1/en - specificDescription = " Dolby Vision"; + specificDescription << " Dolby Vision"; DEBUG_HEVC("ParserAnnexBHEVC::parseAndAddNALUnit Dolby Vision Metadata"); parseResult.nalTypeName = "Dolby Vision "; } @@ -607,7 +608,7 @@ ParserAnnexBHEVC::parseAndAddNALUnit(int } catch (const std::exception &e) { - specificDescription += " ERROR " + std::string(e.what()); + specificDescription << " ERROR " << e.what(); parseResult.success = false; } @@ -655,7 +656,7 @@ ParserAnnexBHEVC::parseAndAddNALUnit(int if (nalRoot) { auto name = "NAL " + std::to_string(nalHEVC->nalIdx) + ": " + - std::to_string(nalHEVC->header.nalUnitTypeID) + specificDescription; + std::to_string(nalHEVC->header.nalUnitTypeID) + specificDescription.str(); nalRoot->setProperties(name); } diff --git a/YUViewLib/src/parser/HEVC/nal_unit_header.h b/YUViewLib/src/parser/HEVC/nal_unit_header.h index 598689327..909234da2 100644 --- a/YUViewLib/src/parser/HEVC/nal_unit_header.h +++ b/YUViewLib/src/parser/HEVC/nal_unit_header.h @@ -32,8 +32,8 @@ #pragma once -#include "common/EnumMapper.h" -#include "parser/common/SubByteReaderLogging.h" +#include +#include namespace parser::hevc { @@ -107,71 +107,72 @@ enum class NalType UNSPECIFIED }; -const EnumMapper NalTypeMapper({{NalType::TRAIL_N, "TRAIL_N"}, - {NalType::TRAIL_R, "TRAIL_R"}, - {NalType::TSA_N, "TSA_N"}, - {NalType::TSA_R, "TSA_R"}, - {NalType::STSA_N, "STSA_N"}, - {NalType::STSA_R, "STSA_R"}, - {NalType::RADL_N, "RADL_N"}, - {NalType::RADL_R, "RADL_R"}, - {NalType::RASL_N, "RASL_N"}, - {NalType::RASL_R, "RASL_R"}, - {NalType::RSV_VCL_N10, "RSV_VCL_N10"}, - {NalType::RSV_VCL_N12, "RSV_VCL_N12"}, - {NalType::RSV_VCL_N14, "RSV_VCL_N14"}, - {NalType::RSV_VCL_R11, "RSV_VCL_R11"}, - {NalType::RSV_VCL_R13, "RSV_VCL_R13"}, - {NalType::RSV_VCL_R15, "RSV_VCL_R15"}, - {NalType::BLA_W_LP, "BLA_W_LP"}, - {NalType::BLA_W_RADL, "BLA_W_RADL"}, - {NalType::BLA_N_LP, "BLA_N_LP"}, - {NalType::IDR_W_RADL, "IDR_W_RADL"}, - {NalType::IDR_N_LP, "IDR_N_LP"}, - {NalType::CRA_NUT, "CRA_NUT"}, - {NalType::RSV_IRAP_VCL22, "RSV_IRAP_VCL22"}, - {NalType::RSV_IRAP_VCL23, "RSV_IRAP_VCL23"}, - {NalType::RSV_VCL24, "RSV_VCL24"}, - {NalType::RSV_VCL25, "RSV_VCL25"}, - {NalType::RSV_VCL26, "RSV_VCL26"}, - {NalType::RSV_VCL27, "RSV_VCL27"}, - {NalType::RSV_VCL28, "RSV_VCL28"}, - {NalType::RSV_VCL29, "RSV_VCL29"}, - {NalType::RSV_VCL30, "RSV_VCL30"}, - {NalType::RSV_VCL31, "RSV_VCL31"}, - {NalType::VPS_NUT, "VPS_NUT"}, - {NalType::SPS_NUT, "SPS_NUT"}, - {NalType::PPS_NUT, "PPS_NUT"}, - {NalType::AUD_NUT, "AUD_NUT"}, - {NalType::EOS_NUT, "EOS_NUT"}, - {NalType::EOB_NUT, "EOB_NUT"}, - {NalType::FD_NUT, "FD_NUT"}, - {NalType::PREFIX_SEI_NUT, "PREFIX_SEI_NUT"}, - {NalType::SUFFIX_SEI_NUT, "SUFFIX_SEI_NUT"}, - {NalType::RSV_NVCL41, "RSV_NVCL41"}, - {NalType::RSV_NVCL42, "RSV_NVCL42"}, - {NalType::RSV_NVCL43, "RSV_NVCL43"}, - {NalType::RSV_NVCL44, "RSV_NVCL44"}, - {NalType::RSV_NVCL45, "RSV_NVCL45"}, - {NalType::RSV_NVCL46, "RSV_NVCL46"}, - {NalType::RSV_NVCL47, "RSV_NVCL47"}, - {NalType::UNSPEC48, "UNSPEC48"}, - {NalType::UNSPEC49, "UNSPEC49"}, - {NalType::UNSPEC50, "UNSPEC50"}, - {NalType::UNSPEC51, "UNSPEC51"}, - {NalType::UNSPEC52, "UNSPEC52"}, - {NalType::UNSPEC53, "UNSPEC53"}, - {NalType::UNSPEC54, "UNSPEC54"}, - {NalType::UNSPEC55, "UNSPEC55"}, - {NalType::UNSPEC56, "UNSPEC56"}, - {NalType::UNSPEC57, "UNSPEC57"}, - {NalType::UNSPEC58, "UNSPEC58"}, - {NalType::UNSPEC69, "UNSPEC69"}, - {NalType::UNSPEC60, "UNSPEC60"}, - {NalType::UNSPEC61, "UNSPEC61"}, - {NalType::UNSPEC62, "UNSPEC62"}, - {NalType::UNSPEC63, "UNSPEC63"}, - {NalType::UNSPECIFIED, "UNSPECIFIED"}}); +constexpr EnumMapper + NalTypeMapper(std::make_pair(NalType::TRAIL_N, "TRAIL_N"sv), + std::make_pair(NalType::TRAIL_R, "TRAIL_R"sv), + std::make_pair(NalType::TSA_N, "TSA_N"sv), + std::make_pair(NalType::TSA_R, "TSA_R"sv), + std::make_pair(NalType::STSA_N, "STSA_N"sv), + std::make_pair(NalType::STSA_R, "STSA_R"sv), + std::make_pair(NalType::RADL_N, "RADL_N"sv), + std::make_pair(NalType::RADL_R, "RADL_R"sv), + std::make_pair(NalType::RASL_N, "RASL_N"sv), + std::make_pair(NalType::RASL_R, "RASL_R"sv), + std::make_pair(NalType::RSV_VCL_N10, "RSV_VCL_N10"sv), + std::make_pair(NalType::RSV_VCL_N12, "RSV_VCL_N12"sv), + std::make_pair(NalType::RSV_VCL_N14, "RSV_VCL_N14"sv), + std::make_pair(NalType::RSV_VCL_R11, "RSV_VCL_R11"sv), + std::make_pair(NalType::RSV_VCL_R13, "RSV_VCL_R13"sv), + std::make_pair(NalType::RSV_VCL_R15, "RSV_VCL_R15"sv), + std::make_pair(NalType::BLA_W_LP, "BLA_W_LP"sv), + std::make_pair(NalType::BLA_W_RADL, "BLA_W_RADL"sv), + std::make_pair(NalType::BLA_N_LP, "BLA_N_LP"sv), + std::make_pair(NalType::IDR_W_RADL, "IDR_W_RADL"sv), + std::make_pair(NalType::IDR_N_LP, "IDR_N_LP"sv), + std::make_pair(NalType::CRA_NUT, "CRA_NUT"sv), + std::make_pair(NalType::RSV_IRAP_VCL22, "RSV_IRAP_VCL22"sv), + std::make_pair(NalType::RSV_IRAP_VCL23, "RSV_IRAP_VCL23"sv), + std::make_pair(NalType::RSV_VCL24, "RSV_VCL24"sv), + std::make_pair(NalType::RSV_VCL25, "RSV_VCL25"sv), + std::make_pair(NalType::RSV_VCL26, "RSV_VCL26"sv), + std::make_pair(NalType::RSV_VCL27, "RSV_VCL27"sv), + std::make_pair(NalType::RSV_VCL28, "RSV_VCL28"sv), + std::make_pair(NalType::RSV_VCL29, "RSV_VCL29"sv), + std::make_pair(NalType::RSV_VCL30, "RSV_VCL30"sv), + std::make_pair(NalType::RSV_VCL31, "RSV_VCL31"sv), + std::make_pair(NalType::VPS_NUT, "VPS_NUT"sv), + std::make_pair(NalType::SPS_NUT, "SPS_NUT"sv), + std::make_pair(NalType::PPS_NUT, "PPS_NUT"sv), + std::make_pair(NalType::AUD_NUT, "AUD_NUT"sv), + std::make_pair(NalType::EOS_NUT, "EOS_NUT"sv), + std::make_pair(NalType::EOB_NUT, "EOB_NUT"sv), + std::make_pair(NalType::FD_NUT, "FD_NUT"sv), + std::make_pair(NalType::PREFIX_SEI_NUT, "PREFIX_SEI_NUT"sv), + std::make_pair(NalType::SUFFIX_SEI_NUT, "SUFFIX_SEI_NUT"sv), + std::make_pair(NalType::RSV_NVCL41, "RSV_NVCL41"sv), + std::make_pair(NalType::RSV_NVCL42, "RSV_NVCL42"sv), + std::make_pair(NalType::RSV_NVCL43, "RSV_NVCL43"sv), + std::make_pair(NalType::RSV_NVCL44, "RSV_NVCL44"sv), + std::make_pair(NalType::RSV_NVCL45, "RSV_NVCL45"sv), + std::make_pair(NalType::RSV_NVCL46, "RSV_NVCL46"sv), + std::make_pair(NalType::RSV_NVCL47, "RSV_NVCL47"sv), + std::make_pair(NalType::UNSPEC48, "UNSPEC48"sv), + std::make_pair(NalType::UNSPEC49, "UNSPEC49"sv), + std::make_pair(NalType::UNSPEC50, "UNSPEC50"sv), + std::make_pair(NalType::UNSPEC51, "UNSPEC51"sv), + std::make_pair(NalType::UNSPEC52, "UNSPEC52"sv), + std::make_pair(NalType::UNSPEC53, "UNSPEC53"sv), + std::make_pair(NalType::UNSPEC54, "UNSPEC54"sv), + std::make_pair(NalType::UNSPEC55, "UNSPEC55"sv), + std::make_pair(NalType::UNSPEC56, "UNSPEC56"sv), + std::make_pair(NalType::UNSPEC57, "UNSPEC57"sv), + std::make_pair(NalType::UNSPEC58, "UNSPEC58"sv), + std::make_pair(NalType::UNSPEC69, "UNSPEC69"sv), + std::make_pair(NalType::UNSPEC60, "UNSPEC60"sv), + std::make_pair(NalType::UNSPEC61, "UNSPEC61"sv), + std::make_pair(NalType::UNSPEC62, "UNSPEC62"sv), + std::make_pair(NalType::UNSPEC63, "UNSPEC63"sv), + std::make_pair(NalType::UNSPECIFIED, "UNSPECIFIED"sv)); class nal_unit_header { diff --git a/YUViewLib/src/parser/VVC/ParserAnnexBVVC.cpp b/YUViewLib/src/parser/VVC/ParserAnnexBVVC.cpp index 0a6b6a150..7a3a30ffc 100644 --- a/YUViewLib/src/parser/VVC/ParserAnnexBVVC.cpp +++ b/YUViewLib/src/parser/VVC/ParserAnnexBVVC.cpp @@ -34,6 +34,7 @@ #include #include +#include #include "SEI/buffering_period.h" #include "SEI/sei_message.h" @@ -68,7 +69,7 @@ namespace { BitratePlotModel::BitrateEntry -createBitrateEntryForAU(ParsingState & parsingState, +createBitrateEntryForAU(ParsingState &parsingState, std::optional bitrateEntry) { BitratePlotModel::BitrateEntry entry; @@ -216,7 +217,7 @@ std::optional ParserAnnexBVVC::getSeekData(int iFrameNr) nal->header.nal_unit_type == NalType::SUFFIX_APS_NUT) { auto aps = std::dynamic_pointer_cast(nal->rbsp); - auto apsType = apsParamTypeMapper.indexOf(aps->aps_params_type); + auto apsType = APSParamTypeMapper.indexOf(aps->aps_params_type); activeAPSNal[{apsType, aps->aps_adaptation_parameter_set_id}] = nal; } } @@ -268,7 +269,7 @@ Ratio ParserAnnexBVVC::getSampleAspectRatio() ParserAnnexB::ParseResult ParserAnnexBVVC::parseAndAddNALUnit(int nalID, - const ByteVector & data, + const ByteVector &data, std::optional bitrateEntry, std::optional nalStartEndPosFile, std::shared_ptr parent) @@ -312,15 +313,15 @@ ParserAnnexBVVC::parseAndAddNALUnit(int reader::SubByteReaderLogging reader(data, nalRoot, "", readOffset); - std::string specificDescription; - auto nalVVC = std::make_shared(nalID, nalStartEndPosFile); - auto updatedParsingState = this->parsingState; + std::stringstream specificDescription; + auto nalVVC = std::make_shared(nalID, nalStartEndPosFile); + auto updatedParsingState = this->parsingState; try { nalVVC->header.parse(reader); - auto nalType = nalVVC->header.nal_unit_type; - specificDescription = " " + NalTypeMapper.getName(nalType); + auto nalType = nalVVC->header.nal_unit_type; + specificDescription << " " << NalTypeMapper.getName(nalType); if (updatedParsingState.NoOutputBeforeRecoveryFlag.count(nalVVC->header.nuh_layer_id) == 0) updatedParsingState.NoOutputBeforeRecoveryFlag[nalVVC->header.nuh_layer_id] = true; @@ -332,7 +333,7 @@ ParserAnnexBVVC::parseAndAddNALUnit(int this->activeParameterSets.vpsMap[newVPS->vps_video_parameter_set_id] = newVPS; - specificDescription += " ID " + std::to_string(newVPS->vps_video_parameter_set_id); + specificDescription << " ID " << newVPS->vps_video_parameter_set_id; nalVVC->rbsp = newVPS; nalVVC->rawData = data; @@ -345,7 +346,7 @@ ParserAnnexBVVC::parseAndAddNALUnit(int this->activeParameterSets.spsMap[newSPS->sps_seq_parameter_set_id] = newSPS; - specificDescription += " ID " + std::to_string(newSPS->sps_seq_parameter_set_id); + specificDescription << " ID " << newSPS->sps_seq_parameter_set_id; nalVVC->rbsp = newSPS; nalVVC->rawData = data; @@ -358,7 +359,7 @@ ParserAnnexBVVC::parseAndAddNALUnit(int this->activeParameterSets.ppsMap[newPPS->pps_pic_parameter_set_id] = newPPS; - specificDescription += " ID " + std::to_string(newPPS->pps_pic_parameter_set_id); + specificDescription << " ID " << newPPS->pps_pic_parameter_set_id; nalVVC->rbsp = newPPS; nalVVC->rawData = data; @@ -369,10 +370,10 @@ ParserAnnexBVVC::parseAndAddNALUnit(int auto newAPS = std::make_shared(); newAPS->parse(reader); - auto apsType = apsParamTypeMapper.indexOf(newAPS->aps_params_type); + auto apsType = APSParamTypeMapper.indexOf(newAPS->aps_params_type); this->activeParameterSets.apsMap[{apsType, newAPS->aps_adaptation_parameter_set_id}] = newAPS; - specificDescription += " ID " + std::to_string(newAPS->aps_adaptation_parameter_set_id); + specificDescription << " ID " << newAPS->aps_adaptation_parameter_set_id; nalVVC->rbsp = newAPS; nalVVC->rawData = data; @@ -410,13 +411,13 @@ ParserAnnexBVVC::parseAndAddNALUnit(int nalType != NalType::RADL_NUT) updatedParsingState.prevTid0Pic[nalVVC->header.nuh_layer_id] = pictureHeader; - specificDescription += " POC " + std::to_string(pictureHeader->PicOrderCntVal); + specificDescription << " POC " << pictureHeader->PicOrderCntVal; nalVVC->rbsp = newPictureHeader; } else if (nalVVC->header.isSlice()) { - specificDescription += " (Slice Header)"; + specificDescription << " (Slice Header)"; auto newSliceLayer = std::make_shared(); newSliceLayer->parse(reader, nalType, @@ -466,10 +467,12 @@ ParserAnnexBVVC::parseAndAddNALUnit(int updatedParsingState.currentPictureHeaderStructure; } - specificDescription += - " POC " + std::to_string(updatedParsingState.currentPictureHeaderStructure->globalPOC); - specificDescription += - " " + to_string(newSliceLayer->slice_header_instance.sh_slice_type) + "-Slice"; + specificDescription << " POC " + << updatedParsingState.currentPictureHeaderStructure->globalPOC; + specificDescription << " " + << SliceTypeMapper.getName( + newSliceLayer->slice_header_instance.sh_slice_type) + << "-Slice"; nalVVC->rbsp = newSliceLayer; @@ -529,7 +532,7 @@ ParserAnnexBVVC::parseAndAddNALUnit(int { updatedParsingState.lastBufferingPeriod = std::dynamic_pointer_cast(newSEI->sei_payload_instance); - specificDescription = " Buffering Period SEI"; + specificDescription << " Buffering Period SEI"; } nalVVC->rbsp = newSEI; @@ -537,7 +540,7 @@ ParserAnnexBVVC::parseAndAddNALUnit(int } catch (const std::exception &e) { - specificDescription += " ERROR " + std::string(e.what()); + specificDescription << " ERROR " << e.what(); parseResult.success = false; } @@ -551,9 +554,8 @@ ParserAnnexBVVC::parseAndAddNALUnit(int parseResult.bitrateEntry = createBitrateEntryForAU(parsingStatePreviousAU, bitrateEntry); if (!this->handleNewAU(parsingStatePreviousAU)) { - specificDescription += " ERROR Adding POC " + - std::to_string(parsingStatePreviousAU.currentAU.poc) + - " to frame list"; + specificDescription << " ERROR Adding POC " << parsingStatePreviousAU.currentAU.poc + << " to frame list"; parseResult.success = false; } @@ -575,7 +577,7 @@ ParserAnnexBVVC::parseAndAddNALUnit(int if (nalRoot) { auto name = "NAL " + std::to_string(nalVVC->nalIdx) + ": " + - std::to_string(nalVVC->header.nalUnitTypeID) + specificDescription; + std::to_string(nalVVC->header.nalUnitTypeID) + specificDescription.str(); nalRoot->setProperties(name); } diff --git a/YUViewLib/src/parser/VVC/adaptation_parameter_set_rbsp.cpp b/YUViewLib/src/parser/VVC/adaptation_parameter_set_rbsp.cpp index beace35a7..a3071aaad 100644 --- a/YUViewLib/src/parser/VVC/adaptation_parameter_set_rbsp.cpp +++ b/YUViewLib/src/parser/VVC/adaptation_parameter_set_rbsp.cpp @@ -46,7 +46,7 @@ void adaptation_parameter_set_rbsp::parse(SubByteReaderLogging &reader) 3, Options().withCheckRange({0, 2}).withMeaningVector( {"ALF parameters", "LMCS parameters", "Scaling list parameters"})); - this->aps_params_type = *apsParamTypeMapper.at(aps_params_type_ID); + this->aps_params_type = *APSParamTypeMapper.at(aps_params_type_ID); this->aps_adaptation_parameter_set_id = reader.readBits("aps_adaptation_parameter_set_id", 5, Options().withCheckRange({0, 7})); diff --git a/YUViewLib/src/parser/VVC/adaptation_parameter_set_rbsp.h b/YUViewLib/src/parser/VVC/adaptation_parameter_set_rbsp.h index 3cea88b9a..69613ad66 100644 --- a/YUViewLib/src/parser/VVC/adaptation_parameter_set_rbsp.h +++ b/YUViewLib/src/parser/VVC/adaptation_parameter_set_rbsp.h @@ -50,9 +50,10 @@ enum class APSParamType SCALING_APS }; -const EnumMapper apsParamTypeMapper({{APSParamType::ALF_APS, "ALF_APS"}, - {APSParamType::LMCS_APS, "LMCS_APS"}, - {APSParamType::SCALING_APS, "SCALING_APS"}}); +constexpr EnumMapper + APSParamTypeMapper(std::make_pair(APSParamType::ALF_APS, "ALF_APS"sv), + std::make_pair(APSParamType::LMCS_APS, "LMCS_APS"sv), + std::make_pair(APSParamType::SCALING_APS, "SCALING_APS"sv)); class adaptation_parameter_set_rbsp : public NalRBSP { diff --git a/YUViewLib/src/parser/VVC/nal_unit_header.h b/YUViewLib/src/parser/VVC/nal_unit_header.h index 4208a42a2..944c65fb3 100644 --- a/YUViewLib/src/parser/VVC/nal_unit_header.h +++ b/YUViewLib/src/parser/VVC/nal_unit_header.h @@ -32,8 +32,8 @@ #pragma once -#include "common/EnumMapper.h" -#include "parser/common/SubByteReaderLogging.h" +#include +#include namespace parser::vvc { @@ -75,39 +75,40 @@ enum class NalType UNSPECIFIED }; -const EnumMapper NalTypeMapper({{NalType::TRAIL_NUT, "TRAIL_NUT"}, - {NalType::STSA_NUT, "STSA_NUT"}, - {NalType::RADL_NUT, "RADL_NUT"}, - {NalType::RASL_NUT, "RASL_NUT"}, - {NalType::RSV_VCL_4, "RSV_VCL_4"}, - {NalType::RSV_VCL_5, "RSV_VCL_5"}, - {NalType::RSV_VCL_6, "RSV_VCL_6"}, - {NalType::IDR_W_RADL, "IDR_W_RADL"}, - {NalType::IDR_N_LP, "IDR_N_LP"}, - {NalType::CRA_NUT, "CRA_NUT"}, - {NalType::GDR_NUT, "GDR_NUT"}, - {NalType::RSV_IRAP_11, "RSV_IRAP_11"}, - {NalType::OPI_NUT, "OPI_NUT"}, - {NalType::DCI_NUT, "DCI_NUT"}, - {NalType::VPS_NUT, "VPS_NUT"}, - {NalType::SPS_NUT, "SPS_NUT"}, - {NalType::PPS_NUT, "PPS_NUT"}, - {NalType::PREFIX_APS_NUT, "PREFIX_APS_NUT"}, - {NalType::SUFFIX_APS_NUT, "SUFFIX_APS_NUT"}, - {NalType::PH_NUT, "PH_NUT"}, - {NalType::AUD_NUT, "AUD_NUT"}, - {NalType::EOS_NUT, "EOS_NUT"}, - {NalType::EOB_NUT, "EOB_NUT"}, - {NalType::PREFIX_SEI_NUT, "PREFIX_SEI_NUT"}, - {NalType::SUFFIX_SEI_NUT, "SUFFIX_SEI_NUT"}, - {NalType::FD_NUT, "FD_NUT"}, - {NalType::RSV_NVCL_26, "RSV_NVCL_26"}, - {NalType::RSV_NVCL_27, "RSV_NVCL_27"}, - {NalType::UNSPEC_28, "UNSPEC_28"}, - {NalType::UNSPEC_29, "UNSPEC_29"}, - {NalType::UNSPEC_30, "UNSPEC_30"}, - {NalType::UNSPEC_31, "UNSPEC_31"}, - {NalType::UNSPECIFIED, "UNSPECIFIED"}}); +constexpr EnumMapper + NalTypeMapper(std::make_pair(NalType::TRAIL_NUT, "TRAIL_NUT"sv), + std::make_pair(NalType::STSA_NUT, "STSA_NUT"sv), + std::make_pair(NalType::RADL_NUT, "RADL_NUT"sv), + std::make_pair(NalType::RASL_NUT, "RASL_NUT"sv), + std::make_pair(NalType::RSV_VCL_4, "RSV_VCL_4"sv), + std::make_pair(NalType::RSV_VCL_5, "RSV_VCL_5"sv), + std::make_pair(NalType::RSV_VCL_6, "RSV_VCL_6"sv), + std::make_pair(NalType::IDR_W_RADL, "IDR_W_RADL"sv), + std::make_pair(NalType::IDR_N_LP, "IDR_N_LP"sv), + std::make_pair(NalType::CRA_NUT, "CRA_NUT"sv), + std::make_pair(NalType::GDR_NUT, "GDR_NUT"sv), + std::make_pair(NalType::RSV_IRAP_11, "RSV_IRAP_11"sv), + std::make_pair(NalType::OPI_NUT, "OPI_NUT"sv), + std::make_pair(NalType::DCI_NUT, "DCI_NUT"sv), + std::make_pair(NalType::VPS_NUT, "VPS_NUT"sv), + std::make_pair(NalType::SPS_NUT, "SPS_NUT"sv), + std::make_pair(NalType::PPS_NUT, "PPS_NUT"sv), + std::make_pair(NalType::PREFIX_APS_NUT, "PREFIX_APS_NUT"sv), + std::make_pair(NalType::SUFFIX_APS_NUT, "SUFFIX_APS_NUT"sv), + std::make_pair(NalType::PH_NUT, "PH_NUT"sv), + std::make_pair(NalType::AUD_NUT, "AUD_NUT"sv), + std::make_pair(NalType::EOS_NUT, "EOS_NUT"sv), + std::make_pair(NalType::EOB_NUT, "EOB_NUT"sv), + std::make_pair(NalType::PREFIX_SEI_NUT, "PREFIX_SEI_NUT"sv), + std::make_pair(NalType::SUFFIX_SEI_NUT, "SUFFIX_SEI_NUT"sv), + std::make_pair(NalType::FD_NUT, "FD_NUT"sv), + std::make_pair(NalType::RSV_NVCL_26, "RSV_NVCL_26"sv), + std::make_pair(NalType::RSV_NVCL_27, "RSV_NVCL_27"sv), + std::make_pair(NalType::UNSPEC_28, "UNSPEC_28"sv), + std::make_pair(NalType::UNSPEC_29, "UNSPEC_29"sv), + std::make_pair(NalType::UNSPEC_30, "UNSPEC_30"sv), + std::make_pair(NalType::UNSPEC_31, "UNSPEC_31"sv), + std::make_pair(NalType::UNSPECIFIED, "UNSPECIFIED"sv)); // 3.1 static inline bool isIRAP(NalType nal_unit_type) diff --git a/YUViewLib/src/parser/VVC/slice_header.cpp b/YUViewLib/src/parser/VVC/slice_header.cpp index b85b05f22..69b52c3d4 100644 --- a/YUViewLib/src/parser/VVC/slice_header.cpp +++ b/YUViewLib/src/parser/VVC/slice_header.cpp @@ -41,15 +41,6 @@ namespace parser::vvc { -std::string to_string(SliceType sliceType) -{ - if (sliceType == SliceType::B) - return "B"; - if (sliceType == SliceType::P) - return "P"; - return "I"; -} - using namespace parser::reader; void slice_header::parse(SubByteReaderLogging & reader, diff --git a/YUViewLib/src/parser/VVC/slice_header.h b/YUViewLib/src/parser/VVC/slice_header.h index 750ec7601..9bafd017a 100644 --- a/YUViewLib/src/parser/VVC/slice_header.h +++ b/YUViewLib/src/parser/VVC/slice_header.h @@ -32,9 +32,11 @@ #pragma once +#include +#include + #include "NalUnitVVC.h" #include "byte_alignment.h" -#include "parser/common/SubByteReaderLogging.h" #include "picture_header_structure.h" #include "pred_weight_table.h" #include "ref_pic_lists.h" @@ -51,18 +53,20 @@ enum class SliceType I }; -std::string to_string(SliceType sliceType); +constexpr EnumMapper SliceTypeMapper(std::make_pair(SliceType::B, "B"sv), + std::make_pair(SliceType::P, "P"sv), + std::make_pair(SliceType::I, "I"sv)); class slice_header : public NalRBSP { public: slice_header() = default; ~slice_header() = default; - void parse(reader::SubByteReaderLogging & reader, + void parse(reader::SubByteReaderLogging &reader, NalType nal_unit_type, - VPSMap & vpsMap, - SPSMap & spsMap, - PPSMap & ppsMap, + VPSMap &vpsMap, + SPSMap &spsMap, + PPSMap &ppsMap, std::shared_ptr sliceLayer, std::shared_ptr picHeader); diff --git a/YUViewLib/src/playlistitem/playlistItemCompressedVideo.cpp b/YUViewLib/src/playlistitem/playlistItemCompressedVideo.cpp index 533e664aa..88864274f 100644 --- a/YUViewLib/src/playlistitem/playlistItemCompressedVideo.cpp +++ b/YUViewLib/src/playlistitem/playlistItemCompressedVideo.cpp @@ -468,8 +468,8 @@ InfoData playlistItemCompressedVideo::getInfo() const // At first append the file information part (path, date created, file size...) // info.items.append(loadingDecoder->getFileInfoList()); - info.items.append( - InfoItem("Reader", QString::fromStdString(InputFormatMapper.getName(this->inputFormat)))); + info.items.append(InfoItem( + "Reader", QString::fromStdString(std::string(InputFormatMapper.getName(this->inputFormat))))); if (this->inputFileFFmpegLoading) { auto l = this->inputFileFFmpegLoading->getLibraryPaths(); @@ -941,7 +941,8 @@ void playlistItemCompressedVideo::createPropertiesWidget() } // Add decoders we can use for (auto e : possibleDecoders) - ui.comboBoxDecoder->addItem(QString::fromStdString(DecoderEngineMapper.getName(e))); + ui.comboBoxDecoder->addItem( + QString::fromStdString(std::string(DecoderEngineMapper.getName(e)))); if (const auto index = vectorIndexOf(possibleDecoders, this->decoderEngine)) ui.comboBoxDecoder->setCurrentIndex(static_cast(index.value())); diff --git a/YUViewLib/src/playlistitem/playlistItemOverlay.cpp b/YUViewLib/src/playlistitem/playlistItemOverlay.cpp index b21773043..e3f5438b9 100644 --- a/YUViewLib/src/playlistitem/playlistItemOverlay.cpp +++ b/YUViewLib/src/playlistitem/playlistItemOverlay.cpp @@ -39,8 +39,8 @@ #include #include -#include #include +#include #define PLAYLISTITEMOVERLAY_DEBUG 0 #if PLAYLISTITEMOVERLAY_DEBUG && !NDEBUG @@ -55,10 +55,10 @@ namespace { -const EnumMapper - overlayLayoutModeMapper({{OverlayLayoutMode::Overlay, "Overlay"}, - {OverlayLayoutMode::Arange, "Average"}, - {OverlayLayoutMode::Custom, "Custom"}}); +constexpr EnumMapper + OverlayLayoutModeMapper(std::make_pair(OverlayLayoutMode::Overlay, "Overlay"sv), + std::make_pair(OverlayLayoutMode::Arange, "Average"sv), + std::make_pair(OverlayLayoutMode::Custom, "Custom"sv)); } @@ -473,7 +473,7 @@ void playlistItemOverlay::savePlaylist(QDomElement &root, const QDir &playlistDi playlistItem::appendPropertiesToPlaylist(d); // Append the overlay properties - d.appendProperiteChild("layoutMode", overlayLayoutModeMapper.getName(this->layoutMode)); + d.appendProperiteChild("layoutMode", OverlayLayoutModeMapper.getName(this->layoutMode)); if (this->layoutMode == OverlayLayoutMode::Overlay) d.appendProperiteChild("overlayMode", QString::number(overlayMode)); else if (this->layoutMode == OverlayLayoutMode::Arange) @@ -530,9 +530,8 @@ playlistItemOverlay *playlistItemOverlay::newPlaylistItemOverlay(const YUViewDom } else { - if (auto mode = overlayLayoutModeMapper.getValue( - root.findChildValue("layoutMode").toStdString(), - EnumMapper::StringType::NameOrIndex)) + if (auto mode = OverlayLayoutModeMapper.getValueFromNameOrIndex( + root.findChildValue("layoutMode").toStdString())) newOverlay->layoutMode = *mode; DEBUG_OVERLAY("playlistItemOverlay::newPlaylistItemOverlay layoutMode %d", newOverlay->layoutMode); diff --git a/YUViewLib/src/playlistitem/playlistItemRawFile.cpp b/YUViewLib/src/playlistitem/playlistItemRawFile.cpp index 10e96bcfd..b9dc1db00 100644 --- a/YUViewLib/src/playlistitem/playlistItemRawFile.cpp +++ b/YUViewLib/src/playlistitem/playlistItemRawFile.cpp @@ -38,6 +38,7 @@ #include #include +#include #include // Activate this if you want to know when which buffer is loaded/converted to image and so on. @@ -58,9 +59,9 @@ constexpr auto RGBA_EXTENSIONS = {"rgba", "gbra", "bgra", "brga", "argb", "agbr" bool isInExtensions(const QString &testValue, const std::initializer_list &extensions) { const auto it = - std::find_if(extensions.begin(), extensions.end(), [testValue](const char *extension) { - return QString(extension) == testValue; - }); + std::find_if(extensions.begin(), + extensions.end(), + [testValue](const char *extension) { return QString(extension) == testValue; }); return it != extensions.end(); } @@ -443,7 +444,7 @@ bool playlistItemRawFile::parseY4MFile() void playlistItemRawFile::setFormatFromFileName() { - auto fileFormat = this->dataSource.guessFormatFromFilename(); + const auto fileFormat = guessFormatFromFilename(this->dataSource.getFileInfo()); if (fileFormat.frameSize.isValid()) { this->video->setFrameSize(fileFormat.frameSize); diff --git a/YUViewLib/src/statistics/ColorMapper.h b/YUViewLib/src/statistics/ColorMapper.h index f502e3b92..d9dee50d5 100644 --- a/YUViewLib/src/statistics/ColorMapper.h +++ b/YUViewLib/src/statistics/ColorMapper.h @@ -78,18 +78,28 @@ enum class PredefinedType Col3_bwg }; -const auto PredefinedTypeMapper = EnumMapper( - {{PredefinedType::Jet, "Jet"}, {PredefinedType::Heat, "Heat"}, - {PredefinedType::Hsv, "Hsv"}, {PredefinedType::Shuffle, "Shuffle"}, - {PredefinedType::Hot, "Hot"}, {PredefinedType::Cool, "Cool"}, - {PredefinedType::Spring, "Spring"}, {PredefinedType::Summer, "Summer"}, - {PredefinedType::Autumn, "Autumn"}, {PredefinedType::Winter, "Winter"}, - {PredefinedType::Gray, "Gray"}, {PredefinedType::Bone, "Bone"}, - {PredefinedType::Copper, "Copper"}, {PredefinedType::Pink, "Pink"}, - {PredefinedType::Lines, "Lines"}, {PredefinedType::Col3_gblr, "Col3_gblr"}, - {PredefinedType::Col3_gwr, "Col3_gwr"}, {PredefinedType::Col3_bblr, "Col3_bblr"}, - {PredefinedType::Col3_bwr, "Col3_bwr"}, {PredefinedType::Col3_bblg, "Col3_bblg"}, - {PredefinedType::Col3_bwg, "Col3_bwg"}}); +constexpr EnumMapper + PredefinedTypeMapper(std::make_pair(PredefinedType::Jet, "Jet"sv), + std::make_pair(PredefinedType::Heat, "Heat"sv), + std::make_pair(PredefinedType::Hsv, "Hsv"sv), + std::make_pair(PredefinedType::Shuffle, "Shuffle"sv), + std::make_pair(PredefinedType::Hot, "Hot"sv), + std::make_pair(PredefinedType::Cool, "Cool"sv), + std::make_pair(PredefinedType::Spring, "Spring"sv), + std::make_pair(PredefinedType::Summer, "Summer"sv), + std::make_pair(PredefinedType::Autumn, "Autumn"sv), + std::make_pair(PredefinedType::Winter, "Winter"sv), + std::make_pair(PredefinedType::Gray, "Gray"sv), + std::make_pair(PredefinedType::Bone, "Bone"sv), + std::make_pair(PredefinedType::Copper, "Copper"sv), + std::make_pair(PredefinedType::Pink, "Pink"sv), + std::make_pair(PredefinedType::Lines, "Lines"sv), + std::make_pair(PredefinedType::Col3_gblr, "Col3_gblr"sv), + std::make_pair(PredefinedType::Col3_gwr, "Col3_gwr"sv), + std::make_pair(PredefinedType::Col3_bblr, "Col3_bblr"sv), + std::make_pair(PredefinedType::Col3_bwr, "Col3_bwr"sv), + std::make_pair(PredefinedType::Col3_bblg, "Col3_bblg"sv), + std::make_pair(PredefinedType::Col3_bwg, "Col3_bwg"sv)); enum class MappingType { @@ -98,9 +108,10 @@ enum class MappingType Predefined }; -const auto MappingTypeMapper = EnumMapper({{MappingType::Gradient, "Gradient"}, - {MappingType::Map, "Map"}, - {MappingType::Predefined, "Predefined"}}); +constexpr EnumMapper + MappingTypeMapper(std::make_pair(MappingType::Gradient, "Gradient"sv), + std::make_pair(MappingType::Map, "Map"sv), + std::make_pair(MappingType::Predefined, "Predefined"sv)); class ColorMapper { diff --git a/YUViewLib/src/ui/PlaybackController.cpp b/YUViewLib/src/ui/PlaybackController.cpp index 150051dd2..becfd4778 100644 --- a/YUViewLib/src/ui/PlaybackController.cpp +++ b/YUViewLib/src/ui/PlaybackController.cpp @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -48,6 +49,16 @@ using namespace std::chrono_literals; #define DEBUG_PLAYBACK(fmt, ...) ((void)0) #endif +namespace +{ + +constexpr EnumMapper + RepeatModeMapper(std::make_pair(PlaybackController::RepeatMode::Off, "Off"sv), + std::make_pair(PlaybackController::RepeatMode::One, "One"sv), + std::make_pair(PlaybackController::RepeatMode::All, "All"sv)); + +} + CountDown::CountDown(const int ticks) { this->tick = ticks; diff --git a/YUViewLib/src/ui/PlaybackController.h b/YUViewLib/src/ui/PlaybackController.h index e17a6a996..7cdb46340 100644 --- a/YUViewLib/src/ui/PlaybackController.h +++ b/YUViewLib/src/ui/PlaybackController.h @@ -90,6 +90,13 @@ class PlaybackController : public QWidget bool setCurrentFrameAndUpdate(int frame, bool updateView = true); + enum class RepeatMode + { + Off, + One, + All + }; + public slots: void on_playPauseButton_clicked(); void on_stopButton_clicked(); @@ -150,14 +157,6 @@ private slots: void startOrUpdateTimer(); void startPlayback(); - enum class RepeatMode - { - Off, - One, - All - }; - EnumMapper RepeatModeMapper{ - {{RepeatMode::Off, "Off"}, {RepeatMode::One, "One"}, {RepeatMode::All, "All"}}}; RepeatMode repeatMode{RepeatMode::Off}; void setRepeatModeAndUpdateIcons(const RepeatMode mode); diff --git a/YUViewLib/src/ui/SettingsDialog.cpp b/YUViewLib/src/ui/SettingsDialog.cpp index d836480b7..339603eae 100644 --- a/YUViewLib/src/ui/SettingsDialog.cpp +++ b/YUViewLib/src/ui/SettingsDialog.cpp @@ -141,13 +141,13 @@ SettingsDialog::SettingsDialog(QWidget *parent) : QDialog(parent) for (const auto &decoder : decoder::DecodersHEVC) ui.comboBoxDefaultHEVC->addItem( - QString::fromStdString(decoder::DecoderEngineMapper.getName(decoder))); + QString::fromStdString(std::string(decoder::DecoderEngineMapper.getName(decoder)))); for (const auto &decoder : decoder::DecodersVVC) ui.comboBoxDefaultVVC->addItem( - QString::fromStdString(decoder::DecoderEngineMapper.getName(decoder))); + QString::fromStdString(std::string(decoder::DecoderEngineMapper.getName(decoder)))); for (const auto &decoder : decoder::DecodersAV1) ui.comboBoxDefaultAV1->addItem( - QString::fromStdString(decoder::DecoderEngineMapper.getName(decoder))); + QString::fromStdString(std::string(decoder::DecoderEngineMapper.getName(decoder)))); ui.comboBoxDefaultHEVC->setCurrentText(settings.value("DefaultDecoderHEVC", 0).toString()); ui.comboBoxDefaultVVC->setCurrentText(settings.value("DefaultDecoderVVC", 0).toString()); diff --git a/YUViewLib/src/ui/Statisticsstylecontrol.cpp b/YUViewLib/src/ui/Statisticsstylecontrol.cpp index 9c671e262..233daa25c 100644 --- a/YUViewLib/src/ui/Statisticsstylecontrol.cpp +++ b/YUViewLib/src/ui/Statisticsstylecontrol.cpp @@ -78,7 +78,7 @@ StatisticsStyleControl::StatisticsStyleControl(QWidget *parent) QSignalBlocker blockerPredefined(this->ui.comboBoxPredefined); for (auto typeName : stats::color::PredefinedTypeMapper.getNames()) - this->ui.comboBoxPredefined->addItem(QString::fromStdString(typeName)); + this->ui.comboBoxPredefined->addItem(QString::fromStdString(std::string(typeName))); this->refreshComboBoxCustomMapFromStorage(); } @@ -320,12 +320,15 @@ void StatisticsStyleControl::on_pushButtonEditMap_clicked() StatisticsStyleControl_ColorMapEditor colorMapEditor(originalColorMap, originalOtherColor, this); - connect(&colorMapEditor, &StatisticsStyleControl_ColorMapEditor::mapChanged, [&]() { - this->currentItem->colorMapper.colorMap = colorMapEditor.getColorMap(); - this->currentItem->colorMapper.colorMapOther = colorMapEditor.getOtherColor(); - this->ui.frameDataColor->setColorMapper(this->currentItem->colorMapper); - emit StyleChanged(); - }); + connect(&colorMapEditor, + &StatisticsStyleControl_ColorMapEditor::mapChanged, + [&]() + { + this->currentItem->colorMapper.colorMap = colorMapEditor.getColorMap(); + this->currentItem->colorMapper.colorMapOther = colorMapEditor.getOtherColor(); + this->ui.frameDataColor->setColorMapper(this->currentItem->colorMapper); + emit StyleChanged(); + }); if (colorMapEditor.exec() == QDialog::Accepted) { diff --git a/YUViewLib/src/video/PixelFormat.h b/YUViewLib/src/video/PixelFormat.h index 729fff1d4..c8edaee2b 100644 --- a/YUViewLib/src/video/PixelFormat.h +++ b/YUViewLib/src/video/PixelFormat.h @@ -35,7 +35,6 @@ #include #include - namespace video { @@ -52,14 +51,17 @@ enum class Endianness Little }; +constexpr auto EndianessMapper = EnumMapper( + std::make_pair(Endianness::Little, "Little"sv), std::make_pair(Endianness::Big, "Big"sv)); + enum class DataLayout { Planar, Packed }; -const auto DataLayoutMapper = - EnumMapper({{DataLayout::Packed, "Packed"}, {DataLayout::Planar, "Planar"}}); +constexpr auto DataLayoutMapper = EnumMapper( + std::make_pair(DataLayout::Packed, "Packed"sv), std::make_pair(DataLayout::Planar, "Planar"sv)); } // namespace video diff --git a/YUViewLib/src/video/rgb/PixelFormatRGB.h b/YUViewLib/src/video/rgb/PixelFormatRGB.h index b1b32bc37..b45205835 100644 --- a/YUViewLib/src/video/rgb/PixelFormatRGB.h +++ b/YUViewLib/src/video/rgb/PixelFormatRGB.h @@ -49,6 +49,11 @@ enum class Channel Alpha }; +constexpr auto ChannelMapper = EnumMapper(std::make_pair(Channel::Red, "Red"sv), + std::make_pair(Channel::Green, "Green"sv), + std::make_pair(Channel::Blue, "Blue"sv), + std::make_pair(Channel::Alpha, "Alpha"sv)); + struct rgba_t { unsigned R{0}, G{0}, B{0}, A{0}; @@ -102,12 +107,13 @@ enum class ChannelOrder BGR }; -const auto ChannelOrderMapper = EnumMapper({{ChannelOrder::RGB, "RGB"}, - {ChannelOrder::RBG, "RBG"}, - {ChannelOrder::GRB, "GRB"}, - {ChannelOrder::GBR, "GBR"}, - {ChannelOrder::BRG, "BRG"}, - {ChannelOrder::BGR, "BGR"}}); +constexpr EnumMapper ChannelOrderMapper(std::make_pair(ChannelOrder::RGB, "RGB"sv), + std::make_pair(ChannelOrder::RBG, "RBG"sv), + std::make_pair(ChannelOrder::GRB, "GRB"sv), + std::make_pair(ChannelOrder::GBR, "GBR"sv), + std::make_pair(ChannelOrder::BRG, "BRG"sv), + std::make_pair(ChannelOrder::BGR, + "BGR"sv)); enum class AlphaMode { @@ -116,8 +122,10 @@ enum class AlphaMode Last }; -const auto AlphaModeMapper = EnumMapper( - {{AlphaMode::None, "None"}, {AlphaMode::First, "First"}, {AlphaMode::Last, "Last"}}); +constexpr auto AlphaModeMapper = + EnumMapper(std::make_pair(AlphaMode::None, "None"sv), + std::make_pair(AlphaMode::First, "First"sv), + std::make_pair(AlphaMode::Last, "Last"sv)); // This class defines a specific RGB format with all properties like order of R/G/B, bitsPerValue, // planarity... diff --git a/YUViewLib/src/video/rgb/PixelFormatRGBGuess.cpp b/YUViewLib/src/video/rgb/PixelFormatRGBGuess.cpp index 55c62a4ec..3c51d153c 100644 --- a/YUViewLib/src/video/rgb/PixelFormatRGBGuess.cpp +++ b/YUViewLib/src/video/rgb/PixelFormatRGBGuess.cpp @@ -48,7 +48,7 @@ std::optional findPixelFormatIndicatorInName(const std::string & std::string matcher = "(?:_|\\.|-)("; std::map stringToMatchingFormat; - for (auto channelOrder : ChannelOrderMapper.getEnums()) + for (const auto &[channelOrder, channelOrderName] : ChannelOrderMapper) { for (auto alphaMode : {AlphaMode::None, AlphaMode::First, AlphaMode::Last}) { @@ -68,7 +68,7 @@ std::optional findPixelFormatIndicatorInName(const std::string & std::string name; if (alphaMode == AlphaMode::First) name += "a"; - name += functions::toLower(ChannelOrderMapper.getName(channelOrder)); + name += functions::toLower(channelOrderName); if (alphaMode == AlphaMode::Last) name += "a"; name += bitDepthString + endiannessName; @@ -95,12 +95,11 @@ std::optional findPixelFormatIndicatorInName(const std::string & std::optional findPixelFormatFromFileExtension(const std::string &ext) { - for (auto channelOrder : ChannelOrderMapper.getEnums()) + for (const auto &[channelOrder, name] : ChannelOrderMapper) { - if (functions::toLower(ext) == functions::toLower(ChannelOrderMapper.getName(channelOrder))) + if (functions::toLower(ext) == functions::toLower(name)) return PixelFormatRGB(8, DataLayout::Packed, channelOrder); } - return {}; } diff --git a/YUViewLib/src/video/rgb/videoHandlerRGB.cpp b/YUViewLib/src/video/rgb/videoHandlerRGB.cpp index c4c075d5e..6ae4be830 100644 --- a/YUViewLib/src/video/rgb/videoHandlerRGB.cpp +++ b/YUViewLib/src/video/rgb/videoHandlerRGB.cpp @@ -34,6 +34,7 @@ #include #include +#include #include #include #include