diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index bd9ef01f9..f4ee6c4b8 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -30,6 +30,8 @@ jobs: make -j$(nproc) - name: Run Unittests run: $GITHUB_WORKSPACE/build/YUViewUnitTest/YUViewUnitTest + env: + QT_QPA_PLATFORM: 'offscreen' build-mac-native: runs-on: ${{ matrix.os }} strategy: @@ -51,6 +53,8 @@ jobs: make -j $(sysctl -n hw.logicalcpu) - name: Run Unittests run: $GITHUB_WORKSPACE/build/YUViewUnitTest/YUViewUnitTest + env: + QT_QPA_PLATFORM: 'offscreen' build-linux-mac: runs-on: ${{ matrix.os }} strategy: @@ -105,6 +109,8 @@ jobs: make -j 4 - name: Run Unittests run: $GITHUB_WORKSPACE/build/YUViewUnitTest/YUViewUnitTest + env: + QT_QPA_PLATFORM: 'offscreen' - name: Build App (Mac) if: runner.os == 'macOS' run: | @@ -153,6 +159,8 @@ jobs: curl -L https://github.com/ChristianFeldmann/YUViewQt/releases/download/QtBase-6.9.0/qtBase-6-9-0-windows-2022.zip -o Qt.zip 7z x Qt.zip echo "${{ github.workspace }}\..\..\YUViewQt\YUViewQt\Qt\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + - name: Test qmake + run : qmake --version - name: Install libde265 run: | curl -L https://github.com/ChristianFeldmann/libde265/releases/download/v1.1/libde265.dll -o libde265.dll @@ -176,20 +184,20 @@ jobs: echo "Creating Build dir and entering it" mkdir build cd build - echo "Qmake Version:" - d:\a\YUViewQt\YUViewQt\Qt\bin\qmake --version echo "Executing qmake..." - d:\a\YUViewQt\YUViewQt\Qt\bin\qmake CONFIG+=UNITTESTS .. + qmake CONFIG+=UNITTESTS .. echo "Executing jom:" jom - name: Run Unittests - run: D:\a\YUView\YUView\build\YUViewUnitTest\YUViewUnitTest + run: ${{ github.workspace }}\build\YUViewUnitTest\YUViewUnitTest + env: + QT_QPA_PLATFORM: 'offscreen' - name: WindeployQT run: | mkdir deploy cd deploy cp ../build/YUViewApp/YUView.exe . - d:\a\YUViewQt\YUViewQt\Qt\bin\windeployqt.exe --release --no-compiler-runtime YUView.exe + windeployqt --release --no-compiler-runtime YUView.exe cp ../openSSL/*.dll . mkdir decoder cp ..\libde265.dll decoder diff --git a/HACKING.md b/HACKING.md index 83a78df6e..86b377159 100644 --- a/HACKING.md +++ b/HACKING.md @@ -1,7 +1,7 @@ # Compiler Requirements MSVC: Visual Studio 2013 Update 5 or newer. -gcc/llvm: C++17 support is required. +gcc/llvm: C++20 support is required. # Coding Conventions diff --git a/YUViewApp/YUViewApp.pro b/YUViewApp/YUViewApp.pro index 29b37ec2b..561012031 100644 --- a/YUViewApp/YUViewApp.pro +++ b/YUViewApp/YUViewApp.pro @@ -2,7 +2,7 @@ QT += core gui widgets opengl xml concurrent network TARGET = YUView TEMPLATE = app -CONFIG += c++17 +CONFIG += c++20 CONFIG -= debug_and_release SOURCES += $$files(src/*.cpp, false) diff --git a/YUViewLib/YUViewLib.pro b/YUViewLib/YUViewLib.pro index 2ac10025a..06e539a8d 100644 --- a/YUViewLib/YUViewLib.pro +++ b/YUViewLib/YUViewLib.pro @@ -2,7 +2,7 @@ QT += core gui widgets opengl xml concurrent network TEMPLATE = lib CONFIG += staticlib -CONFIG += c++17 +CONFIG += c++20 CONFIG -= debug_and_release CONFIG += object_parallel_to_source diff --git a/YUViewLib/src/common/Functions.cpp b/YUViewLib/src/common/Functions.cpp index fbde73ebc..534802bbb 100644 --- a/YUViewLib/src/common/Functions.cpp +++ b/YUViewLib/src/common/Functions.cpp @@ -198,6 +198,32 @@ std::string toLower(const std::string_view str) return lowercaseStr; } +std::vector splitString(const std::string_view str, const char delimiter) +{ + std::vector result; + size_t start = 0; + size_t end = str.find(delimiter); + while (end != std::string_view::npos) + { + result.emplace_back(str.substr(start, end - start)); + start = end + 1; + end = str.find(delimiter, start); + } + if (start != str.size()) + result.emplace_back(str.substr(start)); + return result; +} + +std::string_view stripWhitespace(std::string_view str) +{ + str.remove_prefix(std::min(str.find_first_not_of(" "), str.size())); + + const auto lastNonWhitespace = str.find_last_not_of(" "); + if (lastNonWhitespace != std::string_view::npos) + str.remove_suffix(str.size() - lastNonWhitespace - 1); + return str; +} + ByteVector readData(std::istream &istream, const size_t nrBytes) { ByteVector data; @@ -211,11 +237,12 @@ ByteVector readData(std::istream &istream, const size_t nrBytes) std::optional toUnsigned(const std::string_view text) { unsigned value{}; - const auto result = std::from_chars(text.data(), text.data() + text.size(), value); + const auto endPointer = text.data() + text.size(); + const auto result = std::from_chars(text.data(), endPointer, value); if (result.ec != std::errc()) return {}; - const auto allCharactersParsed = (result.ptr == &(*text.end())); + const auto allCharactersParsed = (result.ptr == endPointer); if (!allCharactersParsed) return {}; @@ -225,11 +252,12 @@ std::optional toUnsigned(const std::string_view text) std::optional toInt(const std::string_view text) { int value{}; - const auto result = std::from_chars(text.data(), text.data() + text.size(), value); + const auto endPointer = text.data() + text.size(); + const auto result = std::from_chars(text.data(), endPointer, value); if (result.ec != std::errc()) return {}; - const auto allCharactersParsed = (result.ptr == &(*text.end())); + const auto allCharactersParsed = (result.ptr == endPointer); if (!allCharactersParsed) return {}; diff --git a/YUViewLib/src/common/Functions.h b/YUViewLib/src/common/Functions.h index 546278d4c..39aad04af 100644 --- a/YUViewLib/src/common/Functions.h +++ b/YUViewLib/src/common/Functions.h @@ -36,6 +36,8 @@ #include #include +#include +#include namespace functions { @@ -77,8 +79,12 @@ template QStringList toQStringList(const std::array toInt(const std::string_view str); +std::vector splitString(const std::string_view str, const char delimiter); +std::string_view stripWhitespace(std::string_view str); + +ByteVector readData(std::istream &istream, const size_t nrBytes); template unsigned clipToUnsigned(T val) { diff --git a/YUViewLib/src/common/FunctionsGui.cpp b/YUViewLib/src/common/FunctionsGui.cpp index e2c973af3..e2fea6dc0 100644 --- a/YUViewLib/src/common/FunctionsGui.cpp +++ b/YUViewLib/src/common/FunctionsGui.cpp @@ -108,40 +108,6 @@ QIcon functionsGui::convertIcon(QString iconPath) return outIcon; } -QPixmap functionsGui::convertPixmap(QString pixmapPath) -{ - QSettings settings; - QString themeName = settings.value("Theme", "Default").toString(); - - // Get the active and inactive colors - QStringList colors = functions::getThemeColors(themeName); - QRgb activeColor; - if (colors.size() == 4) - { - QColor active(colors[1]); - activeColor = active.rgb(); - } - else - activeColor = qRgb(0, 0, 0); - - QImage input(pixmapPath); - - QImage active(input.size(), input.format()); - for (int y = 0; y < input.height(); y++) - { - for (int x = 0; x < input.width(); x++) - { - QRgb in = input.pixel(x, y); - if (qAlpha(in) != 0) - active.setPixel(x, y, activeColor); - else - active.setPixel(x, y, in); - } - } - - return QPixmap::fromImage(active); -} - QString functionsGui::pixelFormatToString(QImage::Format f) { if (f == QImage::Format_Invalid) diff --git a/YUViewLib/src/common/FunctionsGui.h b/YUViewLib/src/common/FunctionsGui.h index 347c5d566..73f2bd035 100644 --- a/YUViewLib/src/common/FunctionsGui.h +++ b/YUViewLib/src/common/FunctionsGui.h @@ -108,6 +108,5 @@ void setupUi(void *ui, void (*setupUi)(void *ui, QWidget *widget)); // Return the icon/pixmap from the given file path (inverted if necessary) QIcon convertIcon(QString iconPath); -QPixmap convertPixmap(QString pixmapPath); } // namespace functionsGui diff --git a/YUViewLib/src/common/Typedef.h b/YUViewLib/src/common/Typedef.h index a1fd7e3ba..94762156f 100644 --- a/YUViewLib/src/common/Typedef.h +++ b/YUViewLib/src/common/Typedef.h @@ -256,50 +256,3 @@ enum recacheIndicator // useless in the cache. }; Q_DECLARE_METATYPE(recacheIndicator) - -#if QT_VERSION <= 0x050700 -// copied from newer version of qglobal.h -template struct QNonConstOverload -{ - template - Q_DECL_CONSTEXPR auto operator()(R (T::*ptr)(Args...)) const Q_DECL_NOTHROW->decltype(ptr) - { - return ptr; - } - template - static Q_DECL_CONSTEXPR auto of(R (T::*ptr)(Args...)) Q_DECL_NOTHROW -> decltype(ptr) - { - return ptr; - } -}; -template struct QConstOverload -{ - template - Q_DECL_CONSTEXPR auto operator()(R (T::*ptr)(Args...) const) const Q_DECL_NOTHROW->decltype(ptr) - { - return ptr; - } - template - static Q_DECL_CONSTEXPR auto of(R (T::*ptr)(Args...) const) Q_DECL_NOTHROW -> decltype(ptr) - { - return ptr; - } -}; -template struct QOverload : QConstOverload, QNonConstOverload -{ - using QConstOverload::of; - using QConstOverload::operator(); - using QNonConstOverload::of; - using QNonConstOverload::operator(); - template - Q_DECL_CONSTEXPR auto operator()(R (*ptr)(Args...)) const Q_DECL_NOTHROW->decltype(ptr) - { - return ptr; - } - template - static Q_DECL_CONSTEXPR auto of(R (*ptr)(Args...)) Q_DECL_NOTHROW -> decltype(ptr) - { - return ptr; - } -}; -#endif diff --git a/YUViewLib/src/common/TypedefQtDeprecated.h b/YUViewLib/src/common/TypedefQtDeprecated.h new file mode 100644 index 000000000..9825017a1 --- /dev/null +++ b/YUViewLib/src/common/TypedefQtDeprecated.h @@ -0,0 +1,42 @@ +/* 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 . + */ + + #pragma once + +#include + +#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0) +constexpr auto QCheckBoxStateChanged = &QCheckBox::checkStateChanged; +#else +constexpr auto QCheckBoxStateChanged = &QCheckBox::stateChanged; +#endif + diff --git a/YUViewLib/src/decoder/decoderFFmpeg.cpp b/YUViewLib/src/decoder/decoderFFmpeg.cpp index d6d88de41..622e56ac6 100644 --- a/YUViewLib/src/decoder/decoderFFmpeg.cpp +++ b/YUViewLib/src/decoder/decoderFFmpeg.cpp @@ -204,14 +204,14 @@ void decoderFFmpeg::copyCurImageToBuffer() for (unsigned plane = 0; plane < pixFmt.getNrPlanes(); plane++) { const auto component = - (plane == 0) ? video::yuv::Component::Luma : video::yuv::Component::Chroma; + (plane == 0) ? video::yuv::Component::Luma : video::yuv::Component::Chroma; auto src = frame.getData(plane); const auto srcLinesize = frame.getLineSize(plane); auto dst = this->currentOutputBuffer.data(); if (plane > 0) dst += (nrBytesY + (plane - 1) * nrBytesC); const auto dstLinesize = - this->frameSize.width / pixFmt.getSubsamplingHor(component) * nrBytesPerSample; + this->frameSize.width / pixFmt.getSubsamplingHor(component) * nrBytesPerSample; const auto height = this->frameSize.height / pixFmt.getSubsamplingVer(component); for (unsigned y = 0; y < height; y++) { @@ -224,10 +224,10 @@ void decoderFFmpeg::copyCurImageToBuffer() else if (this->rawFormat == video::RawFormat::RGB) { const auto pixFmt = this->getRGBPixelFormat(); - const auto nrBytesPerSample = pixFmt.getBitsPerSample() <= 8 ? 1 : 2; + const auto nrBytesPerSample = pixFmt.getBitsPerComponent() <= 8 ? 1 : 2; const auto nrBytesPerComponent = - this->frameSize.width * this->frameSize.height * nrBytesPerSample; - const auto nrBytes = nrBytesPerComponent * pixFmt.nrChannels(); + this->frameSize.width * this->frameSize.height * nrBytesPerSample; + const auto nrBytes = nrBytesPerComponent * pixFmt.getNrChannels(); // Is the output big enough? if (auto c = functions::clipToUnsigned(this->currentOutputBuffer.capacity()); c < nrBytes) @@ -257,7 +257,7 @@ void decoderFFmpeg::copyCurImageToBuffer() else { // We only need to iterate over the image once and copy all values per line at once (RGB(A)) - const auto wDst = this->frameSize.width * nrBytesPerSample * pixFmt.nrChannels(); + const auto wDst = this->frameSize.width * nrBytesPerSample * pixFmt.getNrChannels(); auto src = frame.getData(0); const auto srcLinesize = frame.getLineSize(0); for (unsigned y = 0; y < hDst; y++) @@ -291,9 +291,9 @@ void decoderFFmpeg::cacheCurStatistics() const int16_t mvY = mvs.dst_y - mvs.src_y; this->statisticsData->at(mvs.source < 0 ? 0 : 1) - .addBlockValue(blockX, blockY, mvs.w, mvs.h, (int)mvs.source); + .addBlockValue(blockX, blockY, mvs.w, mvs.h, (int)mvs.source); this->statisticsData->at(mvs.source < 0 ? 2 : 3) - .addBlockVector(blockX, blockY, mvs.w, mvs.h, mvX, mvY); + .addBlockVector(blockX, blockY, mvs.w, mvs.h, mvX, mvY); } } } @@ -339,7 +339,7 @@ bool decoderFFmpeg::pushAVPacket(FFmpeg::AVPacketWrapper &pkt) if (this->flushing) { DEBUG_FFMPEG( - "decoderFFmpeg::pushAVPacket: Error no new packets should be pushed in flushing mode."); + "decoderFFmpeg::pushAVPacket: Error no new packets should be pushed in flushing mode."); return false; } @@ -351,7 +351,7 @@ bool decoderFFmpeg::pushAVPacket(FFmpeg::AVPacketWrapper &pkt) #if DECODERFFMPEG_DEBUG_OUTPUT { QString meaning = - QString("decoderFFmpeg::pushAVPacket: Error sending packet - err %1").arg(retPush); + QString("decoderFFmpeg::pushAVPacket: Error sending packet - err %1").arg(retPush); if (retPush == -1094995529) meaning += " INDA"; // Log the first bytes @@ -379,7 +379,7 @@ bool decoderFFmpeg::pushAVPacket(FFmpeg::AVPacketWrapper &pkt) { // Enough data pushed. Decode and retrieve frames now. DEBUG_FFMPEG( - "decoderFFmpeg::pushAVPacket: Enough data pushed. Decode and retrieve frames now."); + "decoderFFmpeg::pushAVPacket: Enough data pushed. Decode and retrieve frames now."); this->decoderState = DecoderState::RetrieveFrames; return false; } @@ -430,7 +430,7 @@ bool decoderFFmpeg::decodeFrame() void decoderFFmpeg::fillStatisticList(stats::StatisticsData &statisticsData) const { auto sourceColorMapper = - stats::color::ColorMapper({-2, 2}, stats::color::PredefinedType::Col3_bblg); + stats::color::ColorMapper({-2, 2}, stats::color::PredefinedType::Col3_bblg); statisticsData.addStatType(stats::StatisticsType(0, "Source -", sourceColorMapper)); statisticsData.addStatType(stats::StatisticsType(1, "Source +", sourceColorMapper)); @@ -454,7 +454,7 @@ bool decoderFFmpeg::createDecoder(FFmpeg::AVCodecIDWrapper codecID, this->decCtx = this->ff.allocDecoder(this->videoCodec); if (!this->decCtx) return this->setErrorB( - QStringLiteral("Could not allocate video decoder (avcodec_alloc_context3)")); + QStringLiteral("Could not allocate video decoder (avcodec_alloc_context3)")); if (codecpar && !this->ff.configureDecoder(decCtx, codecpar)) return this->setErrorB(QStringLiteral("Unable to configure decoder from codecpar")); @@ -474,13 +474,13 @@ bool decoderFFmpeg::createDecoder(FFmpeg::AVCodecIDWrapper codecID, int ret = this->ff.dictSet(opts, "flags2", "+export_mvs", 0); if (ret < 0) return this->setErrorB( - QStringLiteral("Could not request motion vector retrieval. Return code %1").arg(ret)); + QStringLiteral("Could not request motion vector retrieval. Return code %1").arg(ret)); // Open codec ret = this->ff.avcodecOpen2(decCtx, videoCodec, opts); if (ret < 0) return this->setErrorB( - QStringLiteral("Could not open the video codec (avcodec_open2). Return code %1.").arg(ret)); + QStringLiteral("Could not open the video codec (avcodec_open2). Return code %1.").arg(ret)); this->frame = ff.allocateFrame(); if (!this->frame) diff --git a/YUViewLib/src/ffmpeg/AVPixFmtDescriptorWrapper.cpp b/YUViewLib/src/ffmpeg/AVPixFmtDescriptorWrapper.cpp index e077a62ee..36c8f82b4 100644 --- a/YUViewLib/src/ffmpeg/AVPixFmtDescriptorWrapper.cpp +++ b/YUViewLib/src/ffmpeg/AVPixFmtDescriptorWrapper.cpp @@ -380,7 +380,7 @@ bool AVPixFmtDescriptorWrapper::Flags::operator==( this->floatValues == other.floatValues; } -bool AVPixFmtDescriptorWrapper::operator==(const AVPixFmtDescriptorWrapper &other) +bool AVPixFmtDescriptorWrapper::operator==(const AVPixFmtDescriptorWrapper &other) const { if (this->nb_components != other.nb_components) return false; diff --git a/YUViewLib/src/ffmpeg/AVPixFmtDescriptorWrapper.h b/YUViewLib/src/ffmpeg/AVPixFmtDescriptorWrapper.h index d8642a3a3..3277e5888 100644 --- a/YUViewLib/src/ffmpeg/AVPixFmtDescriptorWrapper.h +++ b/YUViewLib/src/ffmpeg/AVPixFmtDescriptorWrapper.h @@ -103,7 +103,7 @@ class AVPixFmtDescriptorWrapper QString aliases{}; AVComponentDescriptor comp[4]; - bool operator==(const AVPixFmtDescriptorWrapper &a); + bool operator==(const AVPixFmtDescriptorWrapper &a) const; }; } // namespace FFmpeg diff --git a/YUViewLib/src/handler/ItemMemoryHandler.cpp b/YUViewLib/src/handler/ItemMemoryHandler.cpp index 5e5762b7f..009701c52 100644 --- a/YUViewLib/src/handler/ItemMemoryHandler.cpp +++ b/YUViewLib/src/handler/ItemMemoryHandler.cpp @@ -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 . + */ #include "ItemMemoryHandler.h" @@ -48,26 +48,32 @@ namespace itemMemoryHandler struct ItemData { - QString filePath; - QDateTime itemChangedLast; - QString format; - QString toString() const { return QString("File: %1 Last Changed: %2 Format: %3").arg(filePath).arg(itemChangedLast.toString("yy-M-d H-m-s")).arg(format); } + QString filePath; + QDateTime itemChangedLast; + std::string format; + QString toString() const + { + return QString("File: %1 Last Changed: %2 Format: %3") + .arg(filePath) + .arg(itemChangedLast.toString("yy-M-d H-m-s")) + .arg(QString::fromStdString(format)); + } }; QList getAllValidItems() { - QSettings settings; + QSettings settings; QList validItems; - auto timeYesterday = QDateTime::currentDateTime().addDays(-2); + auto timeYesterday = QDateTime::currentDateTime().addDays(-2); auto size = settings.beginReadArray("itemMemory"); - for (int i = 0; i < size; ++i) + for (int i = 0; i < size; ++i) { settings.setArrayIndex(i); ItemData data; - data.filePath = settings.value("filePath").toString(); + data.filePath = settings.value("filePath").toString(); data.itemChangedLast = settings.value("dateChanged").toDateTime(); - data.format = settings.value("format").toString(); + data.format = settings.value("format").toString().toStdString(); if (data.itemChangedLast >= timeYesterday) { validItems.append(data); @@ -86,22 +92,22 @@ QList getAllValidItems() void writeNewItemList(QList newItemList) { QSettings settings; - settings.remove("itemMemory"); // Delete the old list + settings.remove("itemMemory"); // Delete the old list settings.beginWriteArray("itemMemory"); - for (int i = 0; i < newItemList.size(); ++i) + for (int i = 0; i < newItemList.size(); ++i) { const auto &item = newItemList[i]; settings.setArrayIndex(i); settings.setValue("filePath", item.filePath); settings.setValue("dateChanged", QVariant(item.itemChangedLast)); - settings.setValue("format", item.format); + settings.setValue("format", QString::fromStdString(item.format)); DEBUG_MEMORY("writeNewItemList Written item " << item.toString()); } settings.endArray(); } -void itemMemoryAddFormat(QString filePath, QString format) +void itemMemoryAddFormat(const QString &filePath, const std::string &format) { auto validItems = getAllValidItems(); @@ -111,8 +117,8 @@ void itemMemoryAddFormat(QString filePath, QString format) if (validItems[i].filePath == filePath) { validItems[i].itemChangedLast = QDateTime::currentDateTime(); - validItems[i].format = format; - itemUpdated = true; + validItems[i].format = format; + itemUpdated = true; DEBUG_MEMORY("itemMemoryAddFormat Modified item " << validItems[i].toString()); break; } @@ -121,17 +127,17 @@ void itemMemoryAddFormat(QString filePath, QString format) if (!itemUpdated) { ItemData newItem; - newItem.filePath = filePath; + newItem.filePath = filePath; newItem.itemChangedLast = QDateTime::currentDateTime(); - newItem.format = format; + newItem.format = format; validItems.append(newItem); DEBUG_MEMORY("itemMemoryAddFormat Added new item " << newItem.toString()); } - + writeNewItemList(validItems); } -QString itemMemoryGetFormat(QString filePath) +std::optional itemMemoryGetFormat(const QString &filePath) { auto validItems = getAllValidItems(); diff --git a/YUViewLib/src/handler/ItemMemoryHandler.h b/YUViewLib/src/handler/ItemMemoryHandler.h index 000905b10..b82ac9711 100644 --- a/YUViewLib/src/handler/ItemMemoryHandler.h +++ b/YUViewLib/src/handler/ItemMemoryHandler.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 @@ -40,7 +40,7 @@ namespace itemMemoryHandler /* Simple memory that uses QSettings to save the format for a file. * Entries older then 48 hours are automatically deleted. */ -void itemMemoryAddFormat(QString filePath, QString format); -QString itemMemoryGetFormat(QString filePath); +void itemMemoryAddFormat(const QString &filePath, const std::string &format); +std::optional itemMemoryGetFormat(const QString &filePath); } // namespace itemMemoryHandler diff --git a/YUViewLib/src/playlistitem/playlistItemRawFile.cpp b/YUViewLib/src/playlistitem/playlistItemRawFile.cpp index 0cc974027..d3d2054fb 100644 --- a/YUViewLib/src/playlistitem/playlistItemRawFile.cpp +++ b/YUViewLib/src/playlistitem/playlistItemRawFile.cpp @@ -63,9 +63,9 @@ constexpr auto CMYK_EXTENSIONS = {"cmyk"}; 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(); } @@ -122,10 +122,10 @@ playlistItemRawFile::playlistItemRawFile(const QString &rawFilePath, if (!this->parseY4MFile()) return; } - else if (!pixelFormatFromMemory.isEmpty()) + else if (pixelFormatFromMemory) { // Use the format that we got from the memory. Don't do any auto detection. - this->video->setFormatFromString(pixelFormatFromMemory); + this->video->setFormatFromString(*pixelFormatFromMemory); } else if (!frameSize.isValid() && sourcePixelFormat.isEmpty()) { @@ -206,7 +206,7 @@ InfoData playlistItemRawFile::getInfo() const info.items.append(infoItem); const auto nrFrames = - (this->properties().startEndRange.second - this->properties().startEndRange.first + 1); + (this->properties().startEndRange.second - this->properties().startEndRange.first + 1); info.items.append(InfoItem("Num Frames", std::to_string(nrFrames))); info.items.append(InfoItem("Bytes per Frame", std::to_string(this->video->getBytesPerFrame()))); @@ -221,7 +221,7 @@ InfoData playlistItemRawFile::getInfo() const { if ((*fileSize % bpf) != 0) info.items.append(InfoItem( - "Warning"sv, "The file size and the given video size and/or raw format do not match.")); + "Warning"sv, "The file size and the given video size and/or raw format do not match.")); } else info.items.append(InfoItem("Warning"sv, "Could not obtain file size from input.")); @@ -251,7 +251,7 @@ bool playlistItemRawFile::parseY4MFile() unsigned width = 0; unsigned height = 0; auto format = - video::yuv::PixelFormatYUV(video::yuv::Subsampling::YUV_420, 8, video::yuv::PlaneOrder::YUV); + video::yuv::PixelFormatYUV(video::yuv::Subsampling::YUV_420, 8, video::yuv::PlaneOrder::YUV); while (rawData.at(offset++) == ' ') { @@ -389,7 +389,7 @@ bool playlistItemRawFile::parseY4MFile() if (width == 0 || height == 0) return setError( - "Error parsing the Y4M header: The size could not be obtained from the header."); + "Error parsing the Y4M header: The size could not be obtained from the header."); // Next, all frames should follow. Each frame starts with the sequence 'FRAME', followed by a set // of paramters for the frame. The 'FRAME' indicator is terminated by a 0x0A. The list of @@ -452,7 +452,7 @@ bool playlistItemRawFile::parseY4MFile() void playlistItemRawFile::setFormatFromFileName() { const auto fileInfoForGuess = filesource::frameFormatGuess::getFileInfoForGuessFromPath( - this->dataSource.getAbsoluteFilePath()); + this->dataSource.getAbsoluteFilePath()); const auto frameFormat = filesource::frameFormatGuess::guessFrameFormat(fileInfoForGuess); @@ -496,7 +496,7 @@ void playlistItemRawFile::savePlaylist(QDomElement &root, const QDir &playlistDi QUrl fileURL(QString::fromStdString(dataSource.getAbsoluteFilePath())); fileURL.setScheme("file"); auto relativePath = - playlistDir.relativeFilePath(QString::fromStdString(dataSource.getAbsoluteFilePath())); + playlistDir.relativeFilePath(QString::fromStdString(dataSource.getAbsoluteFilePath())); auto d = YUViewDomElement(root.ownerDocument().createElement("playlistItemRawFile")); @@ -523,7 +523,7 @@ playlistItemRawFile *playlistItemRawFile::newplaylistItemRawFile(const YUViewDom // check if file with absolute path exists, otherwise check relative path const auto filePath = - functions::getAbsPathFromAbsAndRel(playlistFilePath, absolutePath, relativePath); + functions::getAbsPathFromAbsAndRel(playlistFilePath, absolutePath, relativePath); if (filePath.isEmpty()) return nullptr; @@ -563,9 +563,9 @@ void playlistItemRawFile::slotVideoPropertiesChanged() { DEBUG_RAWFILE("playlistItemRawFile::slotVideoPropertiesChanged"); - auto currentPixelFormat = video->getFormatAsString(); - if (currentPixelFormat != this->pixelFormatAfterLoading) - itemMemoryHandler::itemMemoryAddFormat(this->properties().name, currentPixelFormat); + const auto currentPixelFormat = video->getFormatAsString(); + if (currentPixelFormat && currentPixelFormat != this->pixelFormatAfterLoading) + itemMemoryHandler::itemMemoryAddFormat(this->properties().name, *currentPixelFormat); } ValuePairListSets playlistItemRawFile::getPixelValues(const QPoint &pixelPos, int frameIdx) diff --git a/YUViewLib/src/playlistitem/playlistItemRawFile.h b/YUViewLib/src/playlistitem/playlistItemRawFile.h index d28688195..c1c75751a 100644 --- a/YUViewLib/src/playlistitem/playlistItemRawFile.h +++ b/YUViewLib/src/playlistitem/playlistItemRawFile.h @@ -64,7 +64,7 @@ class playlistItemRawFile : public playlistItemWithVideo // Create a new playlistItemRawFile from the playlist file entry. Return nullptr if parsing // failed. static playlistItemRawFile *newplaylistItemRawFile(const YUViewDomElement &root, - const QString & playlistFilePath); + const QString &playlistFilePath); virtual bool canBeUsedInProcessing() const override { return true; } @@ -116,5 +116,5 @@ private slots: bool isY4MFile{}; QList y4mFrameIndices; - QString pixelFormatAfterLoading{}; + std::optional pixelFormatAfterLoading{}; }; diff --git a/YUViewLib/src/playlistitem/playlistItemStatisticsFile.cpp b/YUViewLib/src/playlistitem/playlistItemStatisticsFile.cpp index e70c9bd0f..6b3931c3e 100644 --- a/YUViewLib/src/playlistitem/playlistItemStatisticsFile.cpp +++ b/YUViewLib/src/playlistitem/playlistItemStatisticsFile.cpp @@ -103,7 +103,7 @@ InfoData playlistItemStatisticsFile::getInfo() const } playlistItemStatisticsFile *playlistItemStatisticsFile::newplaylistItemStatisticsFile( - const YUViewDomElement &root, const QString &playlistFilePath, OpenMode openMode) + const YUViewDomElement &root, const QString &playlistFilePath, OpenMode openMode) { // Parse the DOM element. It should have all values of a playlistItemStatisticsFile auto absolutePath = root.findChildValue("absolutePath"); @@ -111,7 +111,7 @@ playlistItemStatisticsFile *playlistItemStatisticsFile::newplaylistItemStatistic // check if file with absolute path exists, otherwise check relative path const auto filePath = - functions::getAbsPathFromAbsAndRel(playlistFilePath, absolutePath, relativePath); + functions::getAbsPathFromAbsAndRel(playlistFilePath, absolutePath, relativePath); if (filePath.isEmpty()) return nullptr; @@ -299,12 +299,12 @@ void playlistItemStatisticsFile::openStatisticsFile() this->timer.start(1000, this); this->breakBackgroundAtomic.store(false); this->backgroundParserFuture = QtConcurrent::run( - [=](stats::StatisticsFileBase *file) - { file->readFrameAndTypePositionsFromFile(std::ref(this->breakBackgroundAtomic)); }, - this->file.get()); + [this](stats::StatisticsFileBase *file) + { file->readFrameAndTypePositionsFromFile(std::ref(this->breakBackgroundAtomic)); }, + this->file.get()); DEBUG_STAT( - "playlistItemStatisticsFile::openStatisticsFile File opened. Background parsing started."); + "playlistItemStatisticsFile::openStatisticsFile File opened. Background parsing started."); } // This timer event is called regularly when the background loading process is running. diff --git a/YUViewLib/src/statistics/StatisticUIHandler.cpp b/YUViewLib/src/statistics/StatisticUIHandler.cpp index f9b941449..25567f537 100644 --- a/YUViewLib/src/statistics/StatisticUIHandler.cpp +++ b/YUViewLib/src/statistics/StatisticUIHandler.cpp @@ -40,9 +40,10 @@ #endif #include +#include +#include #include #include -#include namespace stats { @@ -64,7 +65,10 @@ StatisticUIHandler::StatisticUIHandler() Qt::QueuedConnection); } -void StatisticUIHandler::setStatisticsData(StatisticsData *data) { this->statisticsData = data; } +void StatisticUIHandler::setStatisticsData(StatisticsData *data) +{ + this->statisticsData = data; +} QLayout *StatisticUIHandler::createStatisticsHandlerControls(bool recreateControlsOnly) { @@ -72,7 +76,7 @@ QLayout *StatisticUIHandler::createStatisticsHandlerControls(bool recreateContro { // Absolutely always only do this once Q_ASSERT_X( - !ui.created(), Q_FUNC_INFO, "The primary statistics controls must only be created once."); + !ui.created(), Q_FUNC_INFO, "The primary statistics controls must only be created once."); ui.setupUi(); } @@ -93,10 +97,8 @@ QLayout *StatisticUIHandler::createStatisticsHandlerControls(bool recreateContro itemNameCheck->setChecked(statType.render); itemNameCheck->setToolTip(statType.description); ui.gridLayout->addWidget(itemNameCheck, int(row + 2), 0); - connect(itemNameCheck, - &QCheckBox::stateChanged, - this, - &StatisticUIHandler::onStatisticsControlChanged); + connect( + itemNameCheck, QCheckBoxStateChanged, this, &StatisticUIHandler::onStatisticsControlChanged); itemNameCheckBoxes[0].push_back(itemNameCheck); // Append the opacity slider @@ -105,17 +107,16 @@ QLayout *StatisticUIHandler::createStatisticsHandlerControls(bool recreateContro opacitySlider->setMaximum(100); opacitySlider->setValue(statType.alphaFactor); ui.gridLayout->addWidget(opacitySlider, int(row + 2), 1); - connect(opacitySlider, - &QSlider::valueChanged, - this, - &StatisticUIHandler::onStatisticsControlChanged); + connect( + opacitySlider, &QSlider::valueChanged, this, &StatisticUIHandler::onStatisticsControlChanged); itemOpacitySliders[0].push_back(opacitySlider); // Append the change style buttons QPushButton *pushButton = new QPushButton( - functionsGui::convertIcon(":img_edit.png"), QString(), ui.scrollAreaWidgetContents); + functionsGui::convertIcon(":img_edit.png"), QString(), ui.scrollAreaWidgetContents); ui.gridLayout->addWidget(pushButton, int(row + 2), 2); - connect(pushButton, &QPushButton::released, this, [=] { onStyleButtonClicked(row); }); + connect( + pushButton, &QPushButton::released, this, [this, row] { this->onStyleButtonClicked(row); }); itemStyleButtons[0].push_back(pushButton); } @@ -144,7 +145,7 @@ QWidget *StatisticUIHandler::getSecondaryStatisticsHandlerControls(bool recreate if (!this->statisticsData) { DEBUG_STATUI( - "StatisticUIHandler::getSecondaryStatisticsHandlerControls statisticsData not set"); + "StatisticUIHandler::getSecondaryStatisticsHandlerControls statisticsData not set"); return {}; } @@ -159,7 +160,7 @@ QWidget *StatisticUIHandler::getSecondaryStatisticsHandlerControls(bool recreate itemNameCheck->setChecked(statType.render); ui2.gridLayout->addWidget(itemNameCheck, int(row + 2), 0); connect(itemNameCheck, - &QCheckBox::stateChanged, + QCheckBoxStateChanged, this, &StatisticUIHandler::onSecondaryStatisticsControlChanged); itemNameCheckBoxes[1].push_back(itemNameCheck); @@ -178,9 +179,10 @@ QWidget *StatisticUIHandler::getSecondaryStatisticsHandlerControls(bool recreate // Append the change style buttons QPushButton *pushButton = new QPushButton( - functionsGui::convertIcon(":img_edit.png"), QString(), ui2.scrollAreaWidgetContents); + functionsGui::convertIcon(":img_edit.png"), QString(), ui2.scrollAreaWidgetContents); ui2.gridLayout->addWidget(pushButton, int(row + 2), 2); - connect(pushButton, &QPushButton::released, this, [=] { onStyleButtonClicked(row); }); + connect( + pushButton, &QPushButton::released, this, [this, row] { this->onStyleButtonClicked(row); }); itemStyleButtons[1].push_back(pushButton); } @@ -190,7 +192,7 @@ QWidget *StatisticUIHandler::getSecondaryStatisticsHandlerControls(bool recreate if (true || ui2.created()) { QSpacerItem *verticalSpacer = - new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding); + new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding); ui2.gridLayout->addItem(verticalSpacer, int(statTypes.size() + 2), 0, 1, 1); spacerItems[1] = verticalSpacer; } @@ -321,8 +323,8 @@ void StatisticUIHandler::updateStatisticsHandlerControls() } // First run a check if all statisticsTypes are identical - bool controlsStillValid = true; - auto &statTypes = this->statisticsData->getStatisticsTypes(); + bool controlsStillValid = true; + auto &statTypes = this->statisticsData->getStatisticsTypes(); if (statTypes.size() != itemNameCheckBoxes[0].size()) // There are more or less statistics types as before controlsStillValid = false; diff --git a/YUViewLib/src/ui/views/SplitViewWidget.cpp b/YUViewLib/src/ui/views/SplitViewWidget.cpp index 5ad3de2d4..1e71e5aca 100644 --- a/YUViewLib/src/ui/views/SplitViewWidget.cpp +++ b/YUViewLib/src/ui/views/SplitViewWidget.cpp @@ -100,7 +100,7 @@ splitViewWidget::splitViewWidget(QWidget *parent) : MoveAndZoomableView(parent) setContextMenuPolicy(Qt::PreventContextMenu); // No test running yet - connect(&testProgrssUpdateTimer, &QTimer::timeout, this, [=] { updateTestProgress(); }); + connect(&testProgrssUpdateTimer, &QTimer::timeout, this, [this] { updateTestProgress(); }); // Initialize the font and the position of the zoom factor indication zoomFactorFont = QFont(SPLITVIEWWIDGET_ZOOMFACTOR_FONT, SPLITVIEWWIDGET_ZOOMFACTOR_FONTSIZE); @@ -235,7 +235,7 @@ void splitViewWidget::paintEvent(QPaintEvent *) // For the zoom box, calculate the pixel position under the cursor for each view. The following // things are calculated in this function: bool pixelPosInItem[2] = {false, - false}; //< Is the pixel position under the cursor within the item? + false}; //< Is the pixel position under the cursor within the item? QRect zoomPixelRect[2]; //< A QRect around the pixel that is under the cursor if (anyItemsSelected && this->drawZoomBox) { @@ -250,10 +250,10 @@ void splitViewWidget::paintEvent(QPaintEvent *) itemSize[1] = item[view]->getSize().height(); // Is the pixel under the cursor within the item? - pixelPosInItem[view] = (zoomBoxPixelUnderCursor[view].x() >= 0 && - zoomBoxPixelUnderCursor[view].x() < itemSize[0]) && - (zoomBoxPixelUnderCursor[view].y() >= 0 && - zoomBoxPixelUnderCursor[view].y() < itemSize[1]); + pixelPosInItem[view] = + (zoomBoxPixelUnderCursor[view].x() >= 0 && + zoomBoxPixelUnderCursor[view].x() < itemSize[0]) && + (zoomBoxPixelUnderCursor[view].y() >= 0 && zoomBoxPixelUnderCursor[view].y() < itemSize[1]); // Mark the pixel under the cursor with a rectangle around it. if (pixelPosInItem[view]) @@ -270,9 +270,9 @@ void splitViewWidget::paintEvent(QPaintEvent *) { QStringPair itemNamesToDraw = determineItemNamesToDraw(item[0], item[1]); const bool drawItemNames = - (drawItemPathAndNameEnabled && item[0] != nullptr && item[1] != nullptr && - !itemNamesToDraw.first.isEmpty() && !itemNamesToDraw.second.isEmpty() && - item[0]->properties().isFileSource && item[1]->properties().isFileSource); + (drawItemPathAndNameEnabled && item[0] != nullptr && item[1] != nullptr && + !itemNamesToDraw.first.isEmpty() && !itemNamesToDraw.second.isEmpty() && + item[0]->properties().isFileSource && item[1]->properties().isFileSource); // Draw two items (or less, if less items are selected) if (item[0]) @@ -288,7 +288,7 @@ void splitViewWidget::paintEvent(QPaintEvent *) if (!waitingForCaching) { painter.setFont( - QFont(SPLITVIEWWIDGET_PIXEL_VALUES_FONT, SPLITVIEWWIDGET_PIXEL_VALUES_FONTSIZE)); + QFont(SPLITVIEWWIDGET_PIXEL_VALUES_FONT, SPLITVIEWWIDGET_PIXEL_VALUES_FONTSIZE)); item[0]->drawItem(&painter, frame, zoom, drawRawValues); } @@ -344,7 +344,7 @@ void splitViewWidget::paintEvent(QPaintEvent *) if (!waitingForCaching) { painter.setFont( - QFont(SPLITVIEWWIDGET_PIXEL_VALUES_FONT, SPLITVIEWWIDGET_PIXEL_VALUES_FONTSIZE)); + QFont(SPLITVIEWWIDGET_PIXEL_VALUES_FONT, SPLITVIEWWIDGET_PIXEL_VALUES_FONTSIZE)); item[1]->drawItem(&painter, frame, zoom, drawRawValues); } @@ -381,13 +381,13 @@ void splitViewWidget::paintEvent(QPaintEvent *) // is not identical. if (item[0]->getSize().height() != item[1]->getSize().height()) paintPixelRulersY( - painter, item[1], drawArea_botR.y(), xSplit, zoom, centerPoints[1], offset); + painter, item[1], drawArea_botR.y(), xSplit, zoom, centerPoints[1], offset); // Draw the "loading" message (if needed) drawingLoadingMessage[1] = (!playing && item[1]->isLoading()); if (drawingLoadingMessage[1]) drawLoadingMessage( - &painter, QPoint(xSplit + (drawArea_botR.x() - xSplit) / 2, drawArea_botR.y() / 2)); + &painter, QPoint(xSplit + (drawArea_botR.x() - xSplit) / 2, drawArea_botR.y() / 2)); if (drawItemNames) drawItemPathAndName(&painter, xSplit, drawArea_botR.x() - xSplit, itemNamesToDraw.second); @@ -409,7 +409,7 @@ void splitViewWidget::paintEvent(QPaintEvent *) if (!waitingForCaching) { painter.setFont( - QFont(SPLITVIEWWIDGET_PIXEL_VALUES_FONT, SPLITVIEWWIDGET_PIXEL_VALUES_FONTSIZE)); + QFont(SPLITVIEWWIDGET_PIXEL_VALUES_FONT, SPLITVIEWWIDGET_PIXEL_VALUES_FONTSIZE)); item[0]->drawItem(&painter, frame, zoom, drawRawValues); } @@ -562,7 +562,7 @@ void splitViewWidget::updatePixelPositions() // true=right) const auto xSplit = int(drawAreaBotR.x() * splittingPoint); const bool mouseInLeftOrRightView = - (isSplitting() && (this->zoomBoxMousePosition.x() > xSplit)); + (isSplitting() && (this->zoomBoxMousePosition.x() > xSplit)); // The absolute center point of the item under the cursor const auto itemCenterMousePos = (mouseInLeftOrRightView) ? centerPoints[1] + this->moveOffset @@ -570,8 +570,8 @@ void splitViewWidget::updatePixelPositions() // The difference in the item under the mouse (normalized by zoom factor) double diffInItem[2] = { - (double)(itemCenterMousePos.x() - this->zoomBoxMousePosition.x()) / this->zoomFactor + 0.5, - (double)(itemCenterMousePos.y() - this->zoomBoxMousePosition.y()) / this->zoomFactor + 0.5}; + (double)(itemCenterMousePos.x() - this->zoomBoxMousePosition.x()) / this->zoomFactor + 0.5, + (double)(itemCenterMousePos.y() - this->zoomBoxMousePosition.y()) / this->zoomFactor + 0.5}; // We now have the pixel difference value for the item under the cursor. // We now draw one zoom box per view @@ -617,7 +617,7 @@ void splitViewWidget::setZoomBoxPixelUnderCursor(QPoint posA, } void splitViewWidget::paintZoomBox(int view, - QPainter & painter, + QPainter &painter, int xSplit, const QPoint &drawArea_botR, playlistItem *item, @@ -707,8 +707,8 @@ void splitViewWidget::paintZoomBox(int view, "X:%1" "Y:%2" "") - .arg(pixelPos.x()) - .arg(pixelPos.y()); + .arg(pixelPos.x()) + .arg(pixelPos.y()); // If the pixel position is within the item, append information on the pixel vale if (pixelPosInItem) @@ -723,10 +723,9 @@ void splitViewWidget::paintZoomBox(int view, pixelInfoString.append(QString("

%1

").arg(title)); for (int j = 0; j < pixelValues.size(); ++j) pixelInfoString.append( - QString( - "") - .arg(pixelValues[j].first) - .arg(pixelValues[j].second)); + QString("") + .arg(pixelValues[j].first) + .arg(pixelValues[j].second)); pixelInfoString.append("
%1:%2
%1:%2
"); } } @@ -740,12 +739,12 @@ void splitViewWidget::paintZoomBox(int view, // Translate to the position where the text box shall be if (view == 0 && isSplitting()) painter.translate( - xSplit - margin - zoomBoxSize - textDocument.size().width() - padding * 2 + 1, - drawArea_botR.y() - margin - textDocument.size().height() - padding * 2 + 1); + xSplit - margin - zoomBoxSize - textDocument.size().width() - padding * 2 + 1, + drawArea_botR.y() - margin - textDocument.size().height() - padding * 2 + 1); else painter.translate( - drawArea_botR.x() - margin - zoomBoxSize - textDocument.size().width() - padding * 2 + 1, - drawArea_botR.y() - margin - textDocument.size().height() - padding * 2 + 1); + drawArea_botR.x() - margin - zoomBoxSize - textDocument.size().width() - padding * 2 + 1, + drawArea_botR.y() - margin - textDocument.size().height() - padding * 2 + 1); // Draw a black rectangle and then the text on top of that QRect rect(QPoint(0, 0), textDocument.size().toSize() + QSize(2 * padding, 2 * padding)); @@ -803,7 +802,7 @@ void splitViewWidget::paintRegularGrid(QPainter *painter, playlistItem *item) } } -void splitViewWidget::paintPixelRulersX(QPainter & painter, +void splitViewWidget::paintPixelRulersX(QPainter &painter, playlistItem *item, int xPixMin, int xPixMax, @@ -857,7 +856,7 @@ void splitViewWidget::paintPixelRulersX(QPainter & painter, } } -void splitViewWidget::paintPixelRulersY(QPainter & painter, +void splitViewWidget::paintPixelRulersY(QPainter &painter, playlistItem *item, int yPixMax, int xPos, @@ -1000,7 +999,7 @@ void splitViewWidget::mousePressEvent(QMouseEvent *mouse_event) mouse_event->position().x() < (splitPosPix + margin)); #else mouseOverSplitLine = - (mouse_event->x() > (splitPosPix - margin) && mouse_event->x() < (splitPosPix + margin)); + (mouse_event->x() > (splitPosPix - margin) && mouse_event->x() < (splitPosPix + margin)); #endif } @@ -1083,7 +1082,7 @@ QPoint splitViewWidget::getMoveOffsetCoordinateSystemOrigin(const QPointF zoomPo if (zoomPointInRightView) { const auto centerOfRightView = - QPoint(xSplit + (drawAreaBotR.x() - xSplit) / 2, drawAreaBotR.y() / 2); + QPoint(xSplit + (drawAreaBotR.x() - xSplit) / 2, drawAreaBotR.y() / 2); return centerOfRightView; } else @@ -1103,7 +1102,7 @@ void splitViewWidget::onZoomRectUpdateOffsetAndZoom(QRectF zoomRect, double addi return; const auto zoomRectCenterOffset = - zoomRect.center() - this->getMoveOffsetCoordinateSystemOrigin(this->viewZoomingMousePosStart); + zoomRect.center() - this->getMoveOffsetCoordinateSystemOrigin(this->viewZoomingMousePosStart); this->setMoveOffset((this->moveOffset - zoomRectCenterOffset) * additionalZoomFactor); this->setZoomFactor(newZoom); } @@ -1195,7 +1194,7 @@ void splitViewWidget::gridSetCustom(bool) { bool ok; int newValue = QInputDialog::getInt( - this, "Custom grid", "Please select a grid size value in pixels", 64, 1, 2147483647, 1, &ok); + this, "Custom grid", "Please select a grid size value in pixels", 64, 1, 2147483647, 1, &ok); if (ok) { this->regularGridSize = newValue; @@ -1605,9 +1604,9 @@ void splitViewWidget::freezeView(bool freeze) } void splitViewWidget::getViewState(QPointF &offset, - double & zoom, - double & splitPoint, - int & mode) const + double &zoom, + double &splitPoint, + int &mode) const { offset = this->moveOffset; zoom = this->zoomFactor; @@ -1657,14 +1656,15 @@ void splitViewWidget::createMenuActions() const bool menuActionsCreatedYet = bool(this->actionSplitViewGroup); Q_ASSERT_X(!menuActionsCreatedYet, Q_FUNC_INFO, "Only call this initialization function once."); - auto configureAction = [this](QAction & action, + auto configureAction = [this](QAction &action, QActionGroup *const actionGroup, - const QString & text, + const QString &text, const bool checkable, const bool checked, void (splitViewWidget::*func)(bool), const QKeySequence &shortcut = {}, - const bool isEnabled = true) { + const bool isEnabled = true) + { action.setParent(this); action.setCheckable(checkable); action.setChecked(checked); @@ -1701,10 +1701,10 @@ void splitViewWidget::createMenuActions() &splitViewWidget::splitViewComparison); this->actionSplitView[0].setToolTip("Show only one single Item."); this->actionSplitView[1].setToolTip( - "Show two items side-by-side so that the same part of each item is visible."); + "Show two items side-by-side so that the same part of each item is visible."); this->actionSplitView[2].setToolTip( - "Show two items at the same position with a split line that can be " - "moved to reveal either item."); + "Show two items at the same position with a split line that can be " + "moved to reveal either item."); this->actionGridGroup.reset(new QActionGroup(this)); configureAction(this->actionGrid[0], @@ -1742,8 +1742,8 @@ void splitViewWidget::createMenuActions() "Custom...", Checkable(true), this->regularGridSize != 0 && this->regularGridSize != 16 && - this->regularGridSize != 32 && this->regularGridSize != 64 && - this->regularGridSize != 128, + this->regularGridSize != 32 && this->regularGridSize != 64 && + this->regularGridSize != 128, &splitViewWidget::gridSetCustom); configureAction(this->actionGrid[6], this->actionGridGroup.get(), @@ -1789,10 +1789,10 @@ void splitViewWidget::createMenuActions() this->actionSeparateView.setToolTip("Show a second window with another view to the same item. " "Especially helpful for multi screen setups."); this->actionSeparateViewLink.setToolTip( - "Link the second view so that any change in one view is also applied in the other view."); + "Link the second view so that any change in one view is also applied in the other view."); this->actionSeparateViewPlaybackBoth.setToolTip( - "For performance reasons playback only runs in one (the second) view. Activate this to run " - "playback in both views siultaneously."); + "For performance reasons playback only runs in one (the second) view. Activate this to run " + "playback in both views siultaneously."); } configureAction(this->actionFullScreen, @@ -1957,7 +1957,7 @@ void splitViewWidget::testDrawingSpeed() if (selection[0] == nullptr) { QMessageBox::information( - this, "Test error", "Please select an item from the playlist to perform the test on."); + this, "Test error", "Please select an item from the playlist to perform the test on."); return; } @@ -1996,8 +1996,8 @@ void splitViewWidget::addMenuActions(QMenu *menu) separateViewMenu->addAction(!isMasterView ? &this->getOtherWidget()->actionSeparateViewLink : &actionSeparateViewLink); separateViewMenu->addAction(!isMasterView - ? &this->getOtherWidget()->actionSeparateViewPlaybackBoth - : &actionSeparateViewPlaybackBoth); + ? &this->getOtherWidget()->actionSeparateViewPlaybackBoth + : &actionSeparateViewPlaybackBoth); separateViewMenu->setToolTipsVisible(true); menu->addAction(&this->actionFullScreen); @@ -2041,11 +2041,11 @@ void splitViewWidget::testFinished(bool canceled) int64_t msec = testDuration.elapsed(); double rate = 1000.0 * 1000 / msec; QMessageBox::information( - this, - "Test results", - QString("We drew 1000 frames in %1 msec. The draw rate is %2 frames per second.") - .arg(msec) - .arg(rate)); + this, + "Test results", + QString("We drew 1000 frames in %1 msec. The draw rate is %2 frames per second.") + .arg(msec) + .arg(rate)); } QPointer splitViewWidget::getOtherWidget() const diff --git a/YUViewLib/src/video/FrameHandler.cpp b/YUViewLib/src/video/FrameHandler.cpp index 103708d23..19edc5a54 100644 --- a/YUViewLib/src/video/FrameHandler.cpp +++ b/YUViewLib/src/video/FrameHandler.cpp @@ -220,7 +220,7 @@ void FrameHandler::slotVideoControlChanged() // Update the controls and get the new selected size auto newSize = getNewSizeFromControls(); DEBUG_FRAME( - "FrameHandler::slotVideoControlChanged new size %dx%d", newSize.width, newSize.height); + "FrameHandler::slotVideoControlChanged new size %dx%d", newSize.width, newSize.height); if (newSize != frameSize && newSize.isValid()) { @@ -360,9 +360,9 @@ void FrameHandler::drawPixelValues(QPainter *painter, pixVal = getPixelVal(x, y); drawWhite = (qRed(pixVal) < 128 && qGreen(pixVal) < 128 && qBlue(pixVal) < 128); valText = QString("R%1\nG%2\nB%3") - .arg(qRed(pixVal), 0, formatBase) - .arg(qGreen(pixVal), 0, formatBase) - .arg(qBlue(pixVal), 0, formatBase); + .arg(qRed(pixVal), 0, formatBase) + .arg(qGreen(pixVal), 0, formatBase) + .arg(qBlue(pixVal), 0, formatBase); } painter->setPen(drawWhite ? Qt::white : Qt::black); @@ -447,6 +447,29 @@ bool FrameHandler::isPixelDark(const QPoint &pixelPos) return (qRed(pixVal) < 128 && qGreen(pixVal) < 128 && qBlue(pixVal) < 128); } +std::optional FrameHandler::getFormatAsString() const +{ + if (!this->frameSize.isValid()) + return {}; + return std::to_string(this->frameSize.width) + ";" + std::to_string(this->frameSize.height); +} + +bool FrameHandler::setFormatFromString(const std::string_view format) +{ + auto split = functions::splitString(format, ';'); + if (split.size() != 2) + return false; + + const auto width = functions::toUnsigned(split.at(0)); + const auto height = functions::toUnsigned(split.at(1)); + + if (!width || !height) + return false; + + this->setFrameSize(Size(*width, *height)); + return true; +} + QStringPairList FrameHandler::getPixelValues(const QPoint &pixelPos, int, FrameHandler *item2, const int) { @@ -492,23 +515,4 @@ FrameHandler::getPixelValues(const QPoint &pixelPos, int, FrameHandler *item2, c return values; } -bool FrameHandler::setFormatFromString(QString format) -{ - auto split = format.split(";"); - if (split.length() != 2) - return false; - - bool ok; - auto newWidth = unsigned(split[0].toInt(&ok)); - if (!ok) - return false; - - auto newHeight = unsigned(split[1].toInt(&ok)); - if (!ok) - return false; - - this->setFrameSize(Size(newWidth, newHeight)); - return true; -} - } // namespace video diff --git a/YUViewLib/src/video/FrameHandler.h b/YUViewLib/src/video/FrameHandler.h index 13181776c..ffdd50d40 100644 --- a/YUViewLib/src/video/FrameHandler.h +++ b/YUViewLib/src/video/FrameHandler.h @@ -40,6 +40,7 @@ #include #include #include +#include #include "ui_FrameHandler.h" @@ -83,13 +84,10 @@ class FrameHandler : public QObject // Is the current format of the FrameHandler valid? The default implementation will check if the // frameSize is valid but more specialized implementations may also check other things: For // example the videoHandlerYUV also checks if a valid YUV format is set. - virtual bool isFormatValid() const { return frameSize.width > 0 && frameSize.height > 0; } + virtual bool isFormatValid() const { return this->frameSize.isValid(); } - virtual QString getFormatAsString() const - { - return QString("%1;%2").arg(this->frameSize.width).arg(this->frameSize.height); - } - virtual bool setFormatFromString(QString format); + virtual std::optional getFormatAsString() const; + virtual bool setFormatFromString(const std::string_view format); // Calculate the difference of this FrameHandler to another FrameHandler. This // function can be overloaded by more specialized video items. For example the videoHandlerYUV diff --git a/YUViewLib/src/video/PixelFormat.h b/YUViewLib/src/video/PixelFormat.h index 2997ee1a9..8bda4c47b 100644 --- a/YUViewLib/src/video/PixelFormat.h +++ b/YUViewLib/src/video/PixelFormat.h @@ -51,8 +51,8 @@ enum class Endianness Little }; -constexpr EnumMapper EndianessMapper = {std::make_pair(Endianness::Little, "Little"), - std::make_pair(Endianness::Big, "Big")}; +constexpr EnumMapper EndiannessMapper = { + std::make_pair(Endianness::Little, "Little"), std::make_pair(Endianness::Big, "Big")}; enum class DataLayout { @@ -61,7 +61,13 @@ enum class DataLayout }; constexpr EnumMapper DataLayoutMapper = { - std::make_pair(DataLayout::Packed, "Packed"), std::make_pair(DataLayout::Planar, "Planar")}; + std::make_pair(DataLayout::Packed, "Packed"), std::make_pair(DataLayout::Planar, "Planar")}; + +enum class TextRendering +{ + White, + Black +}; } // namespace video diff --git a/YUViewLib/src/video/caching/LoadingThread.h b/YUViewLib/src/video/caching/LoadingThread.h index 68b84b5a3..67d648bd3 100644 --- a/YUViewLib/src/video/caching/LoadingThread.h +++ b/YUViewLib/src/video/caching/LoadingThread.h @@ -68,7 +68,7 @@ class LoadingThread : public QThread connect(worker(), &LoadingWorker::loadingFinished, this, - [=] + [this] { DEBUG_THREAD("loadingThread::quitWhenDone worker done -> quit"); quit(); diff --git a/YUViewLib/src/video/caching/VideoCache.cpp b/YUViewLib/src/video/caching/VideoCache.cpp index 73f775a7b..a1240e17c 100644 --- a/YUViewLib/src/video/caching/VideoCache.cpp +++ b/YUViewLib/src/video/caching/VideoCache.cpp @@ -124,8 +124,8 @@ VideoCache::VideoCache(PlaylistTreeWidget *playlistTreeWidget, &PlaybackController::signalPlaybackStarting, this, &VideoCache::updateCacheQueue); - connect(&statusUpdateTimer, &QTimer::timeout, this, [=] { emit updateCacheStatus(); }); - connect(&testProgrssUpdateTimer, &QTimer::timeout, this, [=] { updateTestProgress(); }); + connect(&statusUpdateTimer, &QTimer::timeout, this, [this] { emit updateCacheStatus(); }); + connect(&testProgrssUpdateTimer, &QTimer::timeout, this, [this] { updateTestProgress(); }); } VideoCache::~VideoCache() diff --git a/YUViewLib/src/video/rgb/ConversionDifferenceRGB.cpp b/YUViewLib/src/video/rgb/ConversionDifferenceRGB.cpp new file mode 100644 index 000000000..66eeb754c --- /dev/null +++ b/YUViewLib/src/video/rgb/ConversionDifferenceRGB.cpp @@ -0,0 +1,224 @@ +/* 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 "ConversionDifferenceRGB.h" + +#include +#include + +#include "ConversionFunctions.h" +#include "video/PixelFormat.h" +#include "video/rgb/ConversionRGB.h" +#include "video/rgb/PixelFormatRGB.h" + +// Restrict is basically a promise to the compiler that for the scope of the pointer, the target of +// the pointer will only be accessed through that pointer (and pointers copied from it). +#if __STDC__ != 1 +#define restrict __restrict /* use implementation __ format */ +#else +#ifndef __STDC_VERSION__ +#define restrict __restrict /* use implementation __ format */ +#else +#if __STDC_VERSION__ < 199901L +#define restrict __restrict /* use implementation __ format */ +#else +#/* all ok */ +#endif +#endif +#endif + +namespace video::rgb +{ + +namespace +{ + +using RenderValue = std::tuple; +RenderValue convertDeltaToRenderValue(const rgba_t &delta, + const bool markDifference, + const int amplificationFactor) +{ + if (markDifference) + { + const auto r = (delta.r == 0) ? 0 : 255; + const auto g = (delta.g == 0) ? 0 : 255; + const auto b = (delta.b == 0) ? 0 : 255; + return {r, g, b}; + } + else + { + const auto r = functions::clip(128 + delta.r * amplificationFactor, 0, 255); + const auto g = functions::clip(128 + delta.g * amplificationFactor, 0, 255); + const auto b = functions::clip(128 + delta.b * amplificationFactor, 0, 255); + return {r, g, b}; + } +} + +std::pair +calculateDifferencePredefinedPixelFormat(const InputFrameParameters &frame1, + const InputFrameParameters &frame2, + const PredefinedPixelFormat predefinedPixelFormat, + const Endianness endianness, + const int amplificationFactor, + const bool markDifference) +{ + if (predefinedPixelFormat != PredefinedPixelFormat::RGB565) + return {}; + + const auto frameSize = Size(std::min(frame1.frameSize.width, frame2.frameSize.width), + std::min(frame1.frameSize.height, frame2.frameSize.height)); + + auto outputImage = + QImage(QSize(frameSize.width, frameSize.height), functionsGui::platformImageFormat(false)); + unsigned char *restrict dst = outputImage.bits(); + + SSE sse; + + auto rawData1 = reinterpret_cast(frame1.rawDataItem.data()); + auto rawData2 = reinterpret_cast(frame2.rawDataItem.data()); + + for (unsigned i = 0; i < frameSize.width * frameSize.height; ++i) + { + const auto rgb1 = extractRGB565Value(rawData1, endianness); + const auto rgb2 = extractRGB565Value(rawData2, endianness); + + const auto delta = rgb1 - rgb2; + + sse.addSample(delta); + + std::tie(dst[2], dst[1], dst[0]) = + convertDeltaToRenderValue(delta, markDifference, amplificationFactor); + dst[3] = 255; + + rawData1 += 2; + rawData2 += 2; + dst += 4; + } + + return {outputImage, sse.getMSE()}; +} + +template +rgba_t getRGBAndConvertEndianness(const DataPointers dataPointers, const Endianness endianness) +{ + constexpr auto bitDepth = + (std::is_same_v ? 8 : (std::is_same_v ? 16 : 32)); + + auto r = *dataPointers.r; + auto g = *dataPointers.g; + auto b = *dataPointers.b; + + if (endianness == Endianness::Big) + { + r = swapBytesEndianness(r); + g = swapBytesEndianness(g); + b = swapBytesEndianness(b); + } + + return rgba_t({.r = static_cast(r), .g = static_cast(g), .b = static_cast(b)}); +} + +template +std::pair calculateDifferenceAndMSE(const InputFrameParameters &frame1, + const InputFrameParameters &frame2, + const PixelFormatRGB &pixelFormat, + const int amplificationFactor, + const bool markDifference) +{ + static_assert(std::is_same_v || std::is_same_v || + std::is_same_v); + + auto dataPointers1 = + calculatePointersToStartOfComponents(frame1.rawDataItem, frame1.frameSize, pixelFormat); + auto dataPointers2 = + calculatePointersToStartOfComponents(frame2.rawDataItem, frame2.frameSize, pixelFormat); + + const auto frameSize = Size(std::min(frame1.frameSize.width, frame2.frameSize.width), + std::min(frame1.frameSize.height, frame2.frameSize.height)); + auto outputImage = QImage(QSize(frameSize.width, frameSize.height), + functionsGui::platformImageFormat(pixelFormat.hasAlpha())); + SSE sse; + + unsigned char *restrict dst = outputImage.bits(); + const auto offsetToNextValue = + (pixelFormat.getDataLayout() == DataLayout::Planar ? 1 : pixelFormat.getNrChannels()); + + for (unsigned i = 0; i < frameSize.width * frameSize.height; ++i) + { + const auto rgb1 = getRGBAndConvertEndianness(dataPointers1, pixelFormat.getEndianness()); + const auto rgb2 = getRGBAndConvertEndianness(dataPointers2, pixelFormat.getEndianness()); + + const auto delta = rgb1 - rgb2; + + sse.addSample(delta); + + std::tie(dst[2], dst[1], dst[0]) = + convertDeltaToRenderValue(delta, markDifference, amplificationFactor); + dst[3] = 255; + + dataPointers1 += offsetToNextValue; + dataPointers2 += offsetToNextValue; + dst += 4; + } + + return {outputImage, sse.getMSE()}; +} + +} // namespace + +std::pair calculateDifferenceAndMSE(const InputFrameParameters &frame1, + const InputFrameParameters &frame2, + const PixelFormatRGB &pixelFormat, + const int amplificationFactor, + const bool markDifference) +{ + if (pixelFormat.getPredefinedPixelFormat()) + return calculateDifferencePredefinedPixelFormat(frame1, + frame2, + *pixelFormat.getPredefinedPixelFormat(), + pixelFormat.getEndianness(), + amplificationFactor, + markDifference); + + if (pixelFormat.getBitsPerComponent() == 8) + return calculateDifferenceAndMSE( + frame1, frame2, pixelFormat, amplificationFactor, markDifference); + + if (pixelFormat.getBitsPerComponent() <= 16) + return calculateDifferenceAndMSE( + frame1, frame2, pixelFormat, amplificationFactor, markDifference); + + return calculateDifferenceAndMSE( + frame1, frame2, pixelFormat, amplificationFactor, markDifference); +} + +} // namespace video::rgb diff --git a/YUViewLib/src/video/rgb/ConversionDifferenceRGB.h b/YUViewLib/src/video/rgb/ConversionDifferenceRGB.h new file mode 100644 index 000000000..089ee4b62 --- /dev/null +++ b/YUViewLib/src/video/rgb/ConversionDifferenceRGB.h @@ -0,0 +1,99 @@ +/* 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 . + */ + +#pragma once + +#include