From c06647a1541cd23cdfe5cd85f7bfda22f8d2b5f1 Mon Sep 17 00:00:00 2001 From: ChristianFeldmann Date: Wed, 27 Nov 2024 22:24:46 +0100 Subject: [PATCH] Redo guessing of file type --- YUViewLib/src/filesource/FrameFormatGuess.cpp | 235 ++++++++++++ ...essFormatFromName.h => FrameFormatGuess.h} | 30 +- .../src/filesource/GuessFormatFromName.cpp | 204 ---------- .../src/playlistitem/playlistItemRawFile.cpp | 23 +- .../src/video/rgb/PixelFormatRGBGuess.cpp | 140 ++++--- YUViewLib/src/video/rgb/PixelFormatRGBGuess.h | 9 +- YUViewLib/src/video/rgb/videoHandlerRGB.cpp | 11 +- YUViewLib/src/video/rgb/videoHandlerRGB.h | 19 +- YUViewLib/src/video/videoHandler.h | 17 +- .../src/video/videoHandlerDifference.cpp | 5 +- YUViewLib/src/video/videoHandlerDifference.h | 8 +- YUViewLib/src/video/videoHandlerResample.cpp | 7 +- YUViewLib/src/video/videoHandlerResample.h | 8 +- YUViewLib/src/video/yuv/PixelFormatYUV.h | 1 + .../src/video/yuv/PixelFormatYUVGuess.cpp | 350 ++++++++++-------- YUViewLib/src/video/yuv/PixelFormatYUVGuess.h | 14 +- YUViewLib/src/video/yuv/videoHandlerYUV.cpp | 23 +- YUViewLib/src/video/yuv/videoHandlerYUV.h | 10 +- YUViewUnitTest/common/Testing.h | 7 + .../filesource/DataSourceLocalFileTest.cpp | 2 +- .../filesource/FormatGuessingParameters.h | 67 ++++ .../guessFormatFromFilenameTest.cpp | 252 ++++++------- .../video/rgb/PixelFormatRGBGuessTest.cpp | 244 +++++------- .../video/yuv/PixelFormatYUVGuessTest.cpp | 335 +++++++---------- 24 files changed, 1048 insertions(+), 973 deletions(-) create mode 100644 YUViewLib/src/filesource/FrameFormatGuess.cpp rename YUViewLib/src/filesource/{GuessFormatFromName.h => FrameFormatGuess.h} (70%) delete mode 100644 YUViewLib/src/filesource/GuessFormatFromName.cpp create mode 100644 YUViewUnitTest/filesource/FormatGuessingParameters.h diff --git a/YUViewLib/src/filesource/FrameFormatGuess.cpp b/YUViewLib/src/filesource/FrameFormatGuess.cpp new file mode 100644 index 000000000..7b07cfb90 --- /dev/null +++ b/YUViewLib/src/filesource/FrameFormatGuess.cpp @@ -0,0 +1,235 @@ +/* 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 "FrameFormatGuess.h" + +#include + +#include + +namespace filesource::frameFormatGuess +{ + +using namespace std::string_view_literals; +using functions::toUnsigned; + +namespace +{ + +GuessedFrameFormat guessFrameSizeFPSAndBitDepthFromName(const std::string &name) +{ + // The regular expressions to match. They are sorted from most detailed to least so that the + // most detailed ones are tested first. + // First matches Something_2160x1440_60_8_more.yuv or omething_2160x1440_60_8b.yuv or + // Something_2160x1440_60Hz_8_more.yuv Second matches Something_2160x1440_60_more.yuv or + // Something_2160x1440_60.yuv Thirs matches Something_2160x1440_more.yuv or + // Something_2160x1440.yuv + const auto REGEXP_LIST = {"([0-9]+)(?:x|X|\\*)([0-9]+)_([0-9]+)(?:Hz)?_([0-9]+)b?[\\._]", + "([0-9]+)(?:x|X|\\*)([0-9]+)_([0-9]+)(?:Hz)?[\\._]", + "([0-9]+)(?:x|X|\\*)([0-9]+)[\\._]"}; + + for (const auto ®ExpStr : REGEXP_LIST) + { + std::smatch frameSizeMatch; + const std::regex strExpr(regExpStr); + if (std::regex_search(name, frameSizeMatch, strExpr)) + { + GuessedFrameFormat result; + + const auto width = toUnsigned(frameSizeMatch[1].str()); + const auto height = toUnsigned(frameSizeMatch[2].str()); + if (width && height) + result.frameSize = Size(*width, *height); + + if (frameSizeMatch.size() >= 4) + if (const auto frameRate = toUnsigned(frameSizeMatch[3].str())) + result.frameRate = *frameRate; + + if (frameSizeMatch.size() >= 5) + if (const auto bitDepth = toUnsigned(frameSizeMatch[4].str())) + result.bitDepth = *bitDepth; + + return result; + } + } + + return {}; +} + +GuessedFrameFormat guessFrameSizeAndFrameRateFromResolutionIndicators(const std::string &name) +{ + using RegexpAndSize = std::pair; + const auto REGEXP_AND_SIZE_LIST = {RegexpAndSize({"1080p([0-9]+)", Size(1920, 1080)}), + RegexpAndSize({"720p([0-9]+)", Size(1280, 720)})}; + + for (const auto &[regExpStr, frameSizeForMatch] : REGEXP_AND_SIZE_LIST) + { + std::smatch frameSizeMatch; + const std::regex strExpr(regExpStr.data()); + if (std::regex_search(name, frameSizeMatch, strExpr)) + { + GuessedFrameFormat result; + + result.frameSize = frameSizeForMatch; + if (const auto frameRate = toUnsigned(frameSizeMatch[1].str())) + result.frameRate = *frameRate; + + return result; + } + } + return {}; +} + +std::optional guessFrameSizeFromAcronymResolutionIndicators(const std::string &name) +{ + const auto nameLower = functions::toLower(name); + if (nameLower.find("_cif") != std::string::npos) + return Size(352, 288); + else if (nameLower.find("_qcif") != std::string::npos) + return Size(176, 144); + else if (nameLower.find("_4cif") != std::string::npos) + return Size(704, 576); + else if (nameLower.find("UHD") != std::string::npos) + return Size(3840, 2160); + else if (nameLower.find("HD") != std::string::npos) + return Size(1920, 1080); + else if (nameLower.find("1080p") != std::string::npos) + return Size(1920, 1080); + else if (nameLower.find("720p") != std::string::npos) + return Size(1280, 720); + + return {}; +} + +std::optional guessFPSFromFPSOrHzIndicators(const std::string &name) +{ + std::smatch frameSizeMatch; + const std::regex strExpr("([0-9]+)(?>FPS|fps|HZ|Hz)"); + if (std::regex_search(name, frameSizeMatch, strExpr)) + return toUnsigned(frameSizeMatch[1].str()); + return {}; +} + +std::optional guessBitDepthFromName(const std::string &name) +{ + const auto REGEXP_LIST = { + "(8|9|10|12|16)-?(?>BIT|Bit|bit)", // E.g. 10bit, 10BIT, 10-bit, 10-BIT + "(?:_|\\.|-)(8|9|10|12|16)b(?:_|\\.|-)" // E.g. _16b_ .8b. -12b- + }; + + for (const auto ®ExpStr : REGEXP_LIST) + { + std::smatch bitDepthMatcher; + const std::regex strExpr(regExpStr); + if (std::regex_search(name, bitDepthMatcher, strExpr)) + { + if (const auto bitDepth = toUnsigned(bitDepthMatcher[1].str())) + return bitDepth; + } + } + + return {}; +} + +std::optional guessIsPackedFromName(const std::string &name) +{ + std::smatch packedMatch; + const std::regex strExpr("(?:_|\\.|-)packed(?:_|\\.|-)"); + if (std::regex_search(name, packedMatch, strExpr)) + return video::DataLayout::Packed; + return {}; +} + +} // namespace + +bool GuessedFrameFormat::operator==(const GuessedFrameFormat &rhs) const +{ + return this->frameSize == rhs.frameSize && // + this->frameRate == rhs.frameRate && // + this->bitDepth == rhs.bitDepth && // + this->dataLayout == rhs.dataLayout; +} + +FileInfoForGuess getFileInfoForGuessFromPath(const std::filesystem::path filePath) +{ + FileInfoForGuess fileInfoForGuess; + + fileInfoForGuess.filename = filePath.filename(); + // Todo: This is not really correct. We only want the direct parents path and not the whole parent + // path. + fileInfoForGuess.parentFolderName = filePath.parent_path(); + + try + { + fileInfoForGuess.fileSize = static_cast(std::filesystem::file_size(filePath)); + } + catch (...) + { + } + + return fileInfoForGuess; +} + +GuessedFrameFormat guessFrameFormat(const FileInfoForGuess &fileInfo) +{ + if (fileInfo.filename.empty()) + return {}; + + GuessedFrameFormat result; + + for (auto const &name : {fileInfo.filename, fileInfo.parentFolderName}) + { + if (!result.frameSize) + result = guessFrameSizeFPSAndBitDepthFromName(name); + + if (!result.frameSize) + result = guessFrameSizeAndFrameRateFromResolutionIndicators(name); + + if (!result.frameSize) + result.frameSize = guessFrameSizeFromAcronymResolutionIndicators(name); + + if (!result.frameSize) + continue; + + if (!result.frameRate) + result.frameRate = guessFPSFromFPSOrHzIndicators(name); + + if (!result.bitDepth) + result.bitDepth = guessBitDepthFromName(name); + + result.dataLayout = guessIsPackedFromName(name); + } + + return result; +} + +} // namespace filesource::frameFormatGuess diff --git a/YUViewLib/src/filesource/GuessFormatFromName.h b/YUViewLib/src/filesource/FrameFormatGuess.h similarity index 70% rename from YUViewLib/src/filesource/GuessFormatFromName.h rename to YUViewLib/src/filesource/FrameFormatGuess.h index 4c216e8ba..104ccd306 100644 --- a/YUViewLib/src/filesource/GuessFormatFromName.h +++ b/YUViewLib/src/filesource/FrameFormatGuess.h @@ -33,17 +33,31 @@ #pragma once #include +#include