/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include "ArSessionMetadata.hpp" #include "Extensions/YamlCppConverters.hpp" #include "Host/SystemInfo.hpp" #include #include #include #include namespace OpenVulkano::AR { ArSessionMetadata::ArSessionMetadata() : ArSessionMetadata(ArType::UNKNOWN, ArDepthFormat::UNAVAILABLE, {0,0}, { 1920, 1440 }, 60) {} ArSessionMetadata::ArSessionMetadata(ArType type, ArDepthFormat format, Math::Range confRange, Math::Vector2ui resolution, float frameRate) : ArSessionMetadata(type, format, confRange, resolution, frameRate, SystemInfo::GetDeviceModelName(), SystemInfo::GetOsNameHumanReadable()) {} ArSessionMetadata ArSessionMetadata::FromXML(const std::filesystem::path& filePath) { pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file(filePath.c_str()); if (!result) throw std::runtime_error("Failed to read metadata xml file."); pugi::xml_node metaNode = doc.child("arPlatformInfo"); const char* type = metaNode.child("type").text().as_string(); int minRange = metaNode.child("minConfidence").text().as_int(); int maxRange = metaNode.child("maxConfidence").text().as_int(); const char* depthType = metaNode.child("depthType").text().as_string(); uint32_t resX = 1920, resY = 1440; auto resNode = metaNode.child("imageResolution"); if (!resNode.empty()) { resX = resNode.child("width").text().as_uint(); resY = resNode.child("height").text().as_uint(); } float frameRate = metaNode.child("frameRate").text().as_float(60); uint32_t version = metaNode.child("version").text().as_uint(1); std::string device = metaNode.child("device").text().as_string("Unknown"); std::string os = metaNode.child("os").text().as_string("iOS"); return { ArType::GetFromHumanReadableName(type), ArDepthFormat::GetFromAltName(depthType).value_or(ArDepthFormat::UNAVAILABLE), Math::Range(minRange, maxRange), Math::Vector2ui(resX, resY), frameRate, device, os, version }; } ArSessionMetadata ArSessionMetadata::FromYaml(const std::filesystem::path& filePath) { std::ifstream fin(filePath); YAML::Node meta = YAML::Load(fin); ArSessionMetadata metadata = { ArType::GetFromName(meta["Type"].Scalar()), ArDepthFormat::GetFromName(meta["DepthType"].Scalar()).value_or(ArDepthFormat::UNAVAILABLE), Math::Range(meta["MinConfidence"].as(), meta["MaxConfidence"].as()), meta["Resolution"].as(), meta["FrameRate"].as(60), meta["Device"].as("Unknown"), meta["OS"].as("Unknown"), meta["Version"].as(3) }; auto recNode = meta["Recording"]; if (recNode.IsMap()) { metadata.recDuration = recNode["Duration"].as(-1); metadata.recFrameCount = recNode["FrameCount"].as(-1); metadata.recSkippedFrames = recNode["SkippedFrames"].as(-1); } metadata.frontSensor = meta["FrontSensor"].as(false); return metadata; } bool ArSessionMetadata::DirHasMetadata(const std::filesystem::path& dirPath) { return std::filesystem::exists(dirPath / RECORDING_METADATA_FILENAME_INFO) || std::filesystem::exists(dirPath / RECORDING_METADATA_FILENAME_XML) || std::filesystem::exists(dirPath / RECORDING_METADATA_FILENAME); } ArSessionMetadata ArSessionMetadata::FromFile(const std::filesystem::path& dirPath) { std::optional metaFromFile; if (!is_directory(dirPath)) throw std::runtime_error("Ar recording path must be a directory!"); std::filesystem::path xmlInfoPath(dirPath / RECORDING_METADATA_FILENAME_INFO); if (std::filesystem::exists(xmlInfoPath)) { metaFromFile = FromXML(xmlInfoPath.string()); } xmlInfoPath = dirPath / RECORDING_METADATA_FILENAME_XML; if (std::filesystem::exists(xmlInfoPath)) { metaFromFile = FromXML(xmlInfoPath.string()); } std::filesystem::path ymlInfoPath = dirPath / RECORDING_METADATA_FILENAME; if (std::filesystem::exists(ymlInfoPath)) { metaFromFile = FromYaml(ymlInfoPath.string()); } if (!metaFromFile) throw std::runtime_error("Ar recording dir is missing platform metadata file!"); metaFromFile->playback = true; return *metaFromFile; } std::string ArSessionMetadata::FinishedRecordingInfoToYaml() const { if (recFrameCount < 1 && recDuration < 1 && recSkippedFrames < 1) return ""; return fmt::format(R"(Recording: Duration: {} FrameCount: {} SkippedFrames: {} )", recDuration, recFrameCount, recSkippedFrames); } std::string ArSessionMetadata::ToYaml() const { return fmt::format(R"(Type: {} DepthType: {} MinConfidence: {} MaxConfidence: {} Resolution: '({},{})' FrameRate: {} Device: {} OS: {} FrontSensor: {} Version: {} {} )", type.GetName(), depthFormat.GetName(), static_cast(confidenceRange.min), static_cast(confidenceRange.max), imageResolution.x, imageResolution.y, frameRate, device, os, frontSensor, version, FinishedRecordingInfoToYaml()); } }