diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e31fc60ba..fdb1114d35 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -185,8 +185,8 @@ endif () if (PAG_USE_QT) # need to set the CMAKE_PREFIX_PATH to local QT installation path, for example : - # set(CMAKE_PREFIX_PATH /Users/username/Qt5.13.0/5.13.0/clang_64/lib/cmake) - find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core) + # set(CMAKE_PREFIX_PATH /Users/username/Qt6.2.0/Qt6.2.0/clang_64/lib/cmake) + find_package(QT NAMES Qt6 REQUIRED COMPONENTS Core) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets OpenGL Quick) list(APPEND PAG_SHARED_LIBS Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::OpenGL Qt${QT_VERSION_MAJOR}::Quick) diff --git a/ohos/libpag/README.md b/ohos/libpag/README.md index fb0b80232f..176020cfa7 100644 --- a/ohos/libpag/README.md +++ b/ohos/libpag/README.md @@ -104,7 +104,7 @@ versions, you can download the precompiled libraries from [here](https://github. - NodeJS 14.14.0+ - Ninja 1.9.0+ - CMake 3.13.0+ -- QT 5.13.0+ +- QT 6.2.0+ - Emscripten 3.1.58+ ### Dependency Management diff --git a/viewer/qml/Main.qml b/viewer/qml/Main.qml index 8771eebafb..952ff7c7d4 100644 --- a/viewer/qml/Main.qml +++ b/viewer/qml/Main.qml @@ -28,6 +28,8 @@ PAGWindow { property int windowTitleBarHeight: isWindows ? 32 : 22 + property int minWindowHeightWithEditPanel: 650 + Settings { id: settings property bool isEditPanelOpen: false @@ -67,6 +69,9 @@ PAGWindow { let preferredSize = pagView.preferredSize; let width = Math.max(viewWindow.minimumWidth, preferredSize.width); let height = Math.max(viewWindow.minimumHeight, preferredSize.height); + if (settings.isEditPanelOpen) { + width += mainForm.rightItem.width + mainForm.splitHandleWidth; + } let x = Math.max(0, oldX - ((width - oldWidth) / 2)); let y = Math.max(50, oldY - ((height - oldHeight) / 2)); settings.lastX = x; @@ -289,9 +294,7 @@ PAGWindow { } function updateProgress() { - let duration = mainForm.pagView.duration; - let displayedTime = duration * mainForm.pagView.progress; - mainForm.controlForm.timeDisplayedText.text = Utils.msToTime(displayedTime); + mainForm.controlForm.timeDisplayedText.text = mainForm.pagView.displayedTime; mainForm.controlForm.currentFrameText.text = mainForm.pagView.currentFrame; mainForm.controlForm.totalFrameText.text = mainForm.pagView.totalFrame; } @@ -312,7 +315,31 @@ PAGWindow { if (mainForm.controlForm.panelsButton.checked !== willOpen) { mainForm.controlForm.panelsButton.checked = willOpen; } + + if (willOpen) { + let widthChange = (mainForm.rightItem.width === 0) ? mainForm.minPanelWidth : mainForm.rightItem.width; + widthChange += mainForm.splitHandleWidth; + if (viewWindow.visibility === Window.FullScreen) { + mainForm.centerItem.width = viewWindow.width - widthChange; + } else { + viewWindow.width = viewWindow.width + widthChange; + } + mainForm.rightItem.width = widthChange; + if (viewWindow.height < minWindowHeightWithEditPanel) { + viewWindow.height = minWindowHeightWithEditPanel; + } + } else { + let widthChange = -1 * mainForm.rightItem.width; + if ((viewWindow.width + widthChange) < viewWindow.minimumWidth) { + viewWindow.width = viewWindow.minimumWidth; + } else { + viewWindow.width = viewWindow.width + widthChange; + } + mainForm.rightItem.width = 0; + } + settings.isEditPanelOpen = willOpen; + mainForm.isEditPanelOpen = willOpen; } function onCommand(command) { @@ -325,14 +352,17 @@ PAGWindow { } else { openFileDialog.currentFolder = StandardPaths.writableLocation(StandardPaths.DocumentsLocation); } - openFileDialog.accepted.disconnect(); + if (openFileDialog.currentAcceptHandler) { + openFileDialog.accepted.disconnect(openFileDialog.currentAcceptHandler); + } openFileDialog.fileMode = FileDialog.OpenFile; openFileDialog.title = qsTr("Open PAG File"); openFileDialog.nameFilters = ["PAG files(*.pag)"]; - openFileDialog.accepted.connect(function () { + openFileDialog.currentAcceptHandler = function () { let filePath = openFileDialog.selectedFile; mainForm.pagView.setFile(filePath); - }); + }; + openFileDialog.accepted.connect(openFileDialog.currentAcceptHandler); openFileDialog.open(); break; case "close-window": diff --git a/viewer/qml/MainForm.qml b/viewer/qml/MainForm.qml index 1049b98031..75665aeff0 100644 --- a/viewer/qml/MainForm.qml +++ b/viewer/qml/MainForm.qml @@ -14,6 +14,8 @@ SplitView { property int minPlayerWidth: 360 + property int minPanelWidth: 300 + property int splitHandleWidth: 0 property int splitHandleHeight: 0 @@ -26,6 +28,8 @@ SplitView { property alias centerItem: centerItem + property alias rightItem: rightItem + property alias controlForm: controlForm anchors.fill: parent orientation: Qt.Horizontal @@ -112,4 +116,39 @@ SplitView { } } } + + PAGRectangle { + id: rightItem + visible: isEditPanelOpen + SplitView.minimumWidth: minPanelWidth + SplitView.preferredWidth: minPanelWidth + color: "#16161d" + radius: 5 + leftTopRadius: false + rightTopRadius: false + rightBottomRadius: false + + PAGRectangle { + id: performance + color: "#16161D" + clip: true + anchors.top: parent.top + anchors.topMargin: 0 + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.left: parent.left + anchors.leftMargin: 0 + anchors.bottom: parent.bottom + anchors.bottomMargin: 0 + radius: 5 + leftTopRadius: false + rightTopRadius: false + leftBottomRadius: false + + Profiler { + id: profilerForm + anchors.fill: parent + } + } + } } diff --git a/viewer/qml/Profiler.qml b/viewer/qml/Profiler.qml new file mode 100644 index 0000000000..975c2c0f4e --- /dev/null +++ b/viewer/qml/Profiler.qml @@ -0,0 +1,297 @@ +import PAG +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls + +Item { + id: element + + property int defaultWidth: 300 + property int defaultHeight: 300 + + property alias graph: graph + property alias graphCanvas: graphCanvas + + width: defaultWidth + height: defaultHeight + + PAGRunTimeModelManager { + id: runTimeModelManager + objectName: "runTimeModelManager" + } + + Column { + spacing: 0 + anchors { + fill: parent + leftMargin: 12 + rightMargin: 12 + } + + Item { + width: parent.width + height: 12 + } + + /* Title */ + Rectangle { + id: profilerTitle + color: "#2D2D37" + height: 25 + anchors.left: parent.left + anchors.right: parent.right + + RowLayout { + anchors.fill: parent + spacing: 0 + + Item { + width: 10 + height: 1 + } + + Label { + id: titleLabel + Layout.alignment: Qt.AlignVCenter + text: qsTr("File Info") + color: "#FFFFFF" + font.pixelSize: 10 + visible: true + } + + Item { + Layout.fillWidth: true + height: 1 + } + } + } + + Item { + width: parent.width + height: 1 + } + + /* File Info */ + GridView { + id: fileInfoView + height: 93 + width: parent.width + cellWidth: width / 4 + cellHeight: 46 + boundsBehavior: Flickable.StopAtBounds + keyNavigationWraps: false + anchors.left: parent.left + anchors.right: parent.right + + model: runTimeModelManager.fileInfoModel + + delegate: Item { + width: fileInfoView.cellWidth + height: fileInfoView.cellHeight + + Rectangle { + height: fileInfoView.cellHeight - 1 + width: fileInfoView.cellWidth - ((index + 1) % 4 === 0 ? 0 : 1) + color: "#2D2D37" + anchors { + left: parent.left + top: parent.top + rightMargin: 1 + bottomMargin: 1 + } + Text { + id: nameText + color: "#9b9b9b" + text: name + font.pixelSize: 9 + renderType: Text.NativeRendering + anchors.top: parent.top + anchors.topMargin: 4 + anchors.left: parent.left + anchors.leftMargin: 8 + } + + Text { + id: valueText + color: "#ffffff" + text: value + verticalAlignment: Text.AlignVCenter + font.pixelSize: 14 + renderType: Text.NativeRendering + anchors.top: nameText.bottom + anchors.topMargin: 2 + anchors.bottom: parent.bottom + anchors.bottomMargin: 2 + anchors.left: nameText.left + anchors.leftMargin: 0 + } + + Text { + id: extText + color: "#9b9b9b" + text: unit + font.pixelSize: 9 + renderType: Text.NativeRendering + anchors.bottom: parent.bottom + anchors.bottomMargin: 5 + anchors.left: valueText.right + anchors.leftMargin: 3 + } + } + } + } + + Item { + width: parent.width + height: 2 + } + + /* performance chart */ + Rectangle { + id: performanceChart + height: 90 + color: "#00000000" + anchors.left: parent.left + anchors.right: parent.right + + Rectangle { + id: graph + height: 90 + color: "#2D2D37" + clip: true + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + Canvas { + id: graphCanvas + + height: 70 + width: graph.width + anchors.bottom: parent.bottom + renderStrategy: Canvas.Cooperative + + onPaint: {} + } + Text { + id: currentFrameText + text: "0/0" + font.pixelSize: 9 + anchors.top: parent.top + anchors.topMargin: 5 + anchors.right: parent.right + anchors.rightMargin: 5 + color: "#9B9B9B" + renderType: Text.NativeRendering + } + } + } + + Item { + width: parent.width + height: 4 + } + + /* Data Statistics */ + Rectangle { + id: statistics + height: 62 + color: "#00000000" + anchors.left: parent.left + anchors.right: parent.right + + ListView { + id: dataListView + + width: parent.width + boundsBehavior: ListView.StopAtBounds + interactive: false + anchors.fill: parent + spacing: 1 + + model: runTimeModelManager.frameDisplayInfoModel + + delegate: Item { + height: 20 + Row { + spacing: 1 + Rectangle { + height: 20 + width: (dataListView.width - 2) / 3 + color: "#2D2D37" + Text { + text: name + font.pixelSize: 10 + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 8 + color: colorCode + renderType: Text.NativeRendering + } + Text { + text: current + font.pixelSize: 12 + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: 8 + color: "white" + renderType: Text.NativeRendering + } + } + Rectangle { + height: 20 + width: (dataListView.width - 2) / 3 + color: "#2D2D37" + Text { + text: "AVG" + font.pixelSize: 10 + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 8 + color: colorCode + renderType: Text.NativeRendering + } + Text { + text: avg + font.pixelSize: 12 + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: 8 + color: "white" + renderType: Text.NativeRendering + } + } + Rectangle { + height: 20 + width: (dataListView.width - 2) / 3 + color: "#2D2D37" + Text { + text: "MAX" + font.pixelSize: 10 + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 8 + color: colorCode + renderType: Text.NativeRendering + } + Text { + text: max + font.pixelSize: 12 + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: 8 + color: "white" + renderType: Text.NativeRendering + } + } + } + } + } + } + + Item { + width: parent.width + height: 20 + } + } +} diff --git a/viewer/res.qrc b/viewer/res.qrc index bb07745699..c8ae0ed018 100644 --- a/viewer/res.qrc +++ b/viewer/res.qrc @@ -24,6 +24,7 @@ qml/Main.qml qml/Menu.qml qml/MainForm.qml + qml/Profiler.qml qml/AboutWindow.qml qml/ControlForm.qml qml/SettingsWindow.qml diff --git a/viewer/src/main.cpp b/viewer/src/main.cpp index 137aa2612c..ac19e799a2 100644 --- a/viewer/src/main.cpp +++ b/viewer/src/main.cpp @@ -21,6 +21,7 @@ #include #include #include "PAGViewer.h" +#include "profiling/PAGRunTimeModelManager.h" #include "rendering/PAGView.h" #include "task/PAGTaskFactory.h" @@ -62,6 +63,7 @@ int main(int argc, char* argv[]) { QApplication::setWindowIcon(QIcon(":/images/window-icon.png")); qmlRegisterType("PAG", 1, 0, "PAGView"); qmlRegisterType("PAG", 1, 0, "PAGTaskFactory"); + qmlRegisterType("PAG", 1, 0, "PAGRunTimeModelManager"); app.openFile(filePath.data()); return QApplication::exec(); diff --git a/viewer/src/profiling/PAGFileInfoModel.cpp b/viewer/src/profiling/PAGFileInfoModel.cpp new file mode 100644 index 0000000000..60b4524c9b --- /dev/null +++ b/viewer/src/profiling/PAGFileInfoModel.cpp @@ -0,0 +1,97 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Tencent is pleased to support the open source community by making libpag available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// unless required by applicable law or agreed to in writing, software distributed under the +// license is distributed on an "as is" basis, without warranties or conditions of any kind, +// either express or implied. see the license for the specific language governing permissions +// and limitations under the license. +// +///////////////////////////////////////////////////////////////////////////////////////////////// + +#include "PAGFileInfoModel.h" +#include "pag/file.h" +#include "pag/pag.h" +#include "utils/StringUtils.h" + +namespace pag { + +PAGFileInfo::PAGFileInfo(const QString& name, const QString& value, const QString& unit) + : name(name), value(value), unit(unit) { +} + +PAGFileInfoModel::PAGFileInfoModel() : QAbstractListModel(nullptr) { +} + +PAGFileInfoModel::PAGFileInfoModel(QObject* parent) : QAbstractListModel(parent) { + beginResetModel(); + fileInfos.emplace_back("Duration", "", "s"); + fileInfos.emplace_back("FrameRate", "", "FPS"); + fileInfos.emplace_back("Width"); + fileInfos.emplace_back("Height"); + fileInfos.emplace_back("Graphics"); + fileInfos.emplace_back("Videos"); + fileInfos.emplace_back("Layers"); + fileInfos.emplace_back("SDK Version"); + endResetModel(); +} + +auto PAGFileInfoModel::data(const QModelIndex& index, int role) const -> QVariant { + if ((index.row() < 0) || (index.row() >= static_cast(fileInfos.size()))) { + return {}; + } + + const PAGFileInfo& fileInfo = fileInfos[index.row()]; + auto fileInfoRole = static_cast(role); + if (fileInfoRole == PAGFileInfoRoles::NameRole) { + return fileInfo.name; + } + if (fileInfoRole == PAGFileInfoRoles::ValueRole) { + return fileInfo.value; + } + if (fileInfoRole == PAGFileInfoRoles::UnitRole) { + return fileInfo.unit; + } + + return {}; +} + +auto PAGFileInfoModel::rowCount(const QModelIndex& parent) const -> int { + Q_UNUSED(parent); + return static_cast(fileInfos.size()); +} + +auto PAGFileInfoModel::resetFile(const std::shared_ptr& pagFile, + const std::string& filePath) -> void { + Q_UNUSED(filePath); + beginResetModel(); + fileInfos.clear(); + fileInfos.emplace_back("Duration", Utils::toQString(pagFile->duration() / 1000000.0), "s"); + fileInfos.emplace_back("FrameRate", Utils::toQString(pagFile->frameRate()), "FPS"); + fileInfos.emplace_back("Width", Utils::toQString(pagFile->width())); + fileInfos.emplace_back("Height", Utils::toQString(pagFile->height())); + auto memorySize = CalculateGraphicsMemory(pagFile->getFile()); + fileInfos.emplace_back("Graphics", Utils::getMemorySizeNumString(memorySize), + Utils::getMemorySizeUnit(memorySize)); + fileInfos.emplace_back("Videos", Utils::toQString(pagFile->numVideos())); + fileInfos.emplace_back("Layers", Utils::toQString(pagFile->getFile()->numLayers())); + auto version = Utils::tagCodeToVersion(pagFile->tagLevel()); + fileInfos.emplace_back("SDK Version", version.c_str()); + endResetModel(); +} + +auto PAGFileInfoModel::roleNames() const -> QHash { + static QHash roles = {{static_cast(PAGFileInfoRoles::NameRole), "name"}, + {static_cast(PAGFileInfoRoles::ValueRole), "value"}, + {static_cast(PAGFileInfoRoles::UnitRole), "unit"}}; + return roles; +} + +} // namespace pag \ No newline at end of file diff --git a/viewer/src/profiling/PAGFileInfoModel.h b/viewer/src/profiling/PAGFileInfoModel.h new file mode 100644 index 0000000000..f2a1cdeb3d --- /dev/null +++ b/viewer/src/profiling/PAGFileInfoModel.h @@ -0,0 +1,53 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Tencent is pleased to support the open source community by making libpag available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// unless required by applicable law or agreed to in writing, software distributed under the +// license is distributed on an "as is" basis, without warranties or conditions of any kind, +// either express or implied. see the license for the specific language governing permissions +// and limitations under the license. +// +///////////////////////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include "pag/pag.h" + +namespace pag { +class PAGFileInfo { + public: + explicit PAGFileInfo(const QString& name, const QString& value = "", const QString& unit = ""); + + QString name = ""; + QString value = ""; + QString unit = ""; +}; + +class PAGFileInfoModel : public QAbstractListModel { + Q_OBJECT + public: + enum class PAGFileInfoRoles { NameRole = Qt::UserRole + 1, ValueRole, UnitRole }; + + PAGFileInfoModel(); + explicit PAGFileInfoModel(QObject* parent); + + auto data(const QModelIndex& index, int role) const -> QVariant override; + auto rowCount(const QModelIndex& parent) const -> int override; + auto resetFile(const std::shared_ptr& pagFile, const std::string& filePath) -> void; + + protected: + auto roleNames() const -> QHash override; + + private: + std::vector fileInfos = {}; +}; + +} // namespace pag \ No newline at end of file diff --git a/viewer/src/profiling/PAGFrameDisplayInfoModel.cpp b/viewer/src/profiling/PAGFrameDisplayInfoModel.cpp new file mode 100644 index 0000000000..2e6bce7cfe --- /dev/null +++ b/viewer/src/profiling/PAGFrameDisplayInfoModel.cpp @@ -0,0 +1,88 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Tencent is pleased to support the open source community by making libpag available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// unless required by applicable law or agreed to in writing, software distributed under the +// license is distributed on an "as is" basis, without warranties or conditions of any kind, +// either express or implied. see the license for the specific language governing permissions +// and limitations under the license. +// +///////////////////////////////////////////////////////////////////////////////////////////////// + +#include "PAGFrameDisplayInfoModel.h" + +namespace pag { + +FrameDisplayInfo::FrameDisplayInfo(const QString& name, const QString& color, int64_t current, + int64_t avg, int64_t max) + : name(name), color(color), current(current), avg(avg), max(max) { +} + +PAGFrameDisplayInfoModel::PAGFrameDisplayInfoModel() : QAbstractListModel(nullptr) { +} + +PAGFrameDisplayInfoModel::PAGFrameDisplayInfoModel(QObject* parent) : QAbstractListModel(parent) { +} + +auto PAGFrameDisplayInfoModel::data(const QModelIndex& index, int role) const -> QVariant { + if ((index.row() < 0) || (index.row() >= static_cast(diplayInfos.size()))) { + return {}; + } + + const auto& item = diplayInfos[index.row()]; + switch (static_cast(role)) { + case PAGFrameDisplayInfoRoles::NameRole: { + return item.name; + } + case PAGFrameDisplayInfoRoles::ColorRole: { + return item.color; + } + case PAGFrameDisplayInfoRoles::CurrentRole: { + return QString::number(item.current); + } + case PAGFrameDisplayInfoRoles::AvgRole: { + return QString::number(item.avg); + } + case PAGFrameDisplayInfoRoles::MaxRole: { + return QString::number(item.max); + } + default: + return {}; + } +} + +auto PAGFrameDisplayInfoModel::rowCount(const QModelIndex& parent) const -> int { + Q_UNUSED(parent); + return static_cast(diplayInfos.size()); +} + +auto PAGFrameDisplayInfoModel::updateData(const FrameDisplayInfo& render, + const FrameDisplayInfo& present, + const FrameDisplayInfo& imageDecode) -> void { + + beginResetModel(); + diplayInfos.clear(); + diplayInfos.push_back(render); + diplayInfos.push_back(imageDecode); + diplayInfos.push_back(present); + endResetModel(); +} + +auto PAGFrameDisplayInfoModel::roleNames() const -> QHash { + static const QHash roles = { + {static_cast(PAGFrameDisplayInfoRoles::NameRole), "name"}, + {static_cast(PAGFrameDisplayInfoRoles::ColorRole), "colorCode"}, + {static_cast(PAGFrameDisplayInfoRoles::CurrentRole), "current"}, + {static_cast(PAGFrameDisplayInfoRoles::AvgRole), "avg"}, + {static_cast(PAGFrameDisplayInfoRoles::MaxRole), "max"}}; + return roles; +} + +} // namespace pag \ No newline at end of file diff --git a/viewer/src/profiling/PAGFrameDisplayInfoModel.h b/viewer/src/profiling/PAGFrameDisplayInfoModel.h new file mode 100644 index 0000000000..d33969bd8a --- /dev/null +++ b/viewer/src/profiling/PAGFrameDisplayInfoModel.h @@ -0,0 +1,64 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Tencent is pleased to support the open source community by making libpag available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// unless required by applicable law or agreed to in writing, software distributed under the +// license is distributed on an "as is" basis, without warranties or conditions of any kind, +// either express or implied. see the license for the specific language governing permissions +// and limitations under the license. +// +///////////////////////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include + +namespace pag { + +class FrameDisplayInfo { + public: + FrameDisplayInfo(const QString& name, const QString& color, int64_t current, int64_t avg, + int64_t max); + + QString name = ""; + QString color = ""; + int64_t current = 0; + int64_t avg = 0; + int64_t max = 0; +}; + +class PAGFrameDisplayInfoModel : public QAbstractListModel { + Q_OBJECT + public: + enum class PAGFrameDisplayInfoRoles { + NameRole = Qt::UserRole + 1, + ColorRole, + CurrentRole, + AvgRole, + MaxRole + }; + + PAGFrameDisplayInfoModel(); + explicit PAGFrameDisplayInfoModel(QObject* parent); + + auto data(const QModelIndex& index, int role) const -> QVariant override; + auto rowCount(const QModelIndex& parent) const -> int override; + auto updateData(const FrameDisplayInfo& render, const FrameDisplayInfo& present, + const FrameDisplayInfo& imageDecode) -> void; + + protected: + auto roleNames() const -> QHash override; + + private: + std::vector diplayInfos = {}; +}; + +} // namespace pag \ No newline at end of file diff --git a/viewer/src/profiling/PAGRunTimeModelManager.cpp b/viewer/src/profiling/PAGRunTimeModelManager.cpp new file mode 100644 index 0000000000..d984700e14 --- /dev/null +++ b/viewer/src/profiling/PAGRunTimeModelManager.cpp @@ -0,0 +1,118 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Tencent is pleased to support the open source community by making libpag available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// unless required by applicable law or agreed to in writing, software distributed under the +// license is distributed on an "as is" basis, without warranties or conditions of any kind, +// either express or implied. see the license for the specific language governing permissions +// and limitations under the license. +// +///////////////////////////////////////////////////////////////////////////////////////////////// + +#include "PAGRunTimeModelManager.h" +#include "base/utils/TimeUtil.h" +#include "pag/pag.h" + +namespace pag { + +FrameTimeMetrics::FrameTimeMetrics(int64_t renderTime, int64_t presentTime, int64_t imageDecodeTime) + : renderTime(renderTime), presentTime(presentTime), imageDecodeTime(imageDecodeTime) { +} + +PAGRunTimeModelManager::PAGRunTimeModelManager(QObject* parent) : QObject(parent) { +} + +auto PAGRunTimeModelManager::getTotalFrame() const -> QString { + return QString::number(totalFrame); +} + +auto PAGRunTimeModelManager::getCurrentFrame() const -> QString { + return QString::number(currentFrame); +} + +auto PAGRunTimeModelManager::getFileInfoModel() const -> const PAGFileInfoModel* { + return &fileInfoModel; +} + +auto PAGRunTimeModelManager::getFrameDisplayInfoModel() const -> const PAGFrameDisplayInfoModel* { + return &frameDisplayInfoModel; +} + +auto PAGRunTimeModelManager::setCurrentFrame(const QString& currentFrame) -> void { + if (this->currentFrame == currentFrame.toLongLong()) { + return; + } + this->currentFrame = currentFrame.toLongLong(); + Q_EMIT dataChanged(); +} + +auto PAGRunTimeModelManager::updateData(int64_t currentFrame, int64_t renderTime, + int64_t presentTime, int64_t imageDecodeTime) -> void { + if (this->currentFrame == currentFrame) { + return; + } + this->currentFrame = currentFrame; + if (currentFrame >= frameTimeMetricsVector.size()) { + frameTimeMetricsVector.push_back(FrameTimeMetrics(renderTime, presentTime, imageDecodeTime)); + } else { + frameTimeMetricsVector[currentFrame] = + FrameTimeMetrics(renderTime, presentTime, imageDecodeTime); + } + updateFrameDisplayInfo(renderTime, presentTime, imageDecodeTime); + Q_EMIT dataChanged(); +} + +auto PAGRunTimeModelManager::resetFile(const std::shared_ptr& pagFile, + const std::string& filePath) -> void { + totalFrame = TimeToFrame(pagFile->duration(), pagFile->frameRate()); + currentFrame = -1; + frameTimeMetricsVector.resize(totalFrame, {0, 0, 0}); + frameTimeMetricsVector.squeeze(); + frameTimeMetricsVector.clear(); + fileInfoModel.resetFile(pagFile, filePath); + updateFrameDisplayInfo(0, 0, 0); + Q_EMIT dataChanged(); +} + +auto PAGRunTimeModelManager::updateFrameDisplayInfo(int64_t renderTime, int64_t presentTime, + int64_t imageDecodeTime) -> void { + int64_t renderAvg = 0; + int64_t renderMax = 0; + int64_t renderTotal = 0; + int64_t presentAvg = 0; + int64_t presentMax = 0; + int64_t presentTotal = 0; + int64_t imageDecodeAvg = 0; + int64_t imageDecodeMax = 0; + int64_t imageDecodeTotal = 0; + int64_t size = static_cast(frameTimeMetricsVector.size()); + + if (size > 0) { + for (auto& item : frameTimeMetricsVector) { + renderTotal += item.renderTime; + renderMax = std::max(item.renderTime, renderMax); + presentTotal += item.presentTime; + presentMax = std::max(item.presentTime, presentMax); + imageDecodeTotal += item.imageDecodeTime; + imageDecodeMax = std::max(item.imageDecodeTime, imageDecodeMax); + } + renderAvg = renderTotal / size; + presentAvg = presentTotal / size; + imageDecodeAvg = imageDecodeTotal / size; + } + + FrameDisplayInfo renderInfo("Render", "#0096D8", renderTime, renderAvg, renderMax); + FrameDisplayInfo presentInfo("Present", "#DDB259", presentTime, presentAvg, presentMax); + FrameDisplayInfo imageDecodeInfo("Image", "#74AD59", imageDecodeTime, imageDecodeAvg, + imageDecodeMax); + frameDisplayInfoModel.updateData(renderInfo, presentInfo, imageDecodeInfo); +} + +} // namespace pag \ No newline at end of file diff --git a/viewer/src/profiling/PAGRunTimeModelManager.h b/viewer/src/profiling/PAGRunTimeModelManager.h new file mode 100644 index 0000000000..23d9883235 --- /dev/null +++ b/viewer/src/profiling/PAGRunTimeModelManager.h @@ -0,0 +1,78 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Tencent is pleased to support the open source community by making libpag available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// unless required by applicable law or agreed to in writing, software distributed under the +// license is distributed on an "as is" basis, without warranties or conditions of any kind, +// either express or implied. see the license for the specific language governing permissions +// and limitations under the license. +// +///////////////////////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include "profiling/PAGFileInfoModel.h" +#include "profiling/PAGFrameDisplayInfoModel.h" + +namespace pag { + +class FrameTimeMetrics { + public: + FrameTimeMetrics(int64_t renderTime, int64_t presentTime, int64_t imageDecodeTime); + + int64_t renderTime = 0; + int64_t presentTime = 0; + int64_t imageDecodeTime = 0; +}; + +class PAGRunTimeModelManager : public QObject { + Q_OBJECT + public: + explicit PAGRunTimeModelManager(QObject* parent = nullptr); + + Q_PROPERTY(QString totalFrame READ getTotalFrame NOTIFY totalFrameChanged) + Q_PROPERTY( + QString currentFrame READ getCurrentFrame WRITE setCurrentFrame NOTIFY currentFrameChanged) + Q_PROPERTY( + const PAGFileInfoModel* fileInfoModel READ getFileInfoModel NOTIFY fileInfoModelChanged) + Q_PROPERTY(const PAGFrameDisplayInfoModel* frameDisplayInfoModel READ getFrameDisplayInfoModel + NOTIFY frameDisplayInfoModelChanged) + + auto getTotalFrame() const -> QString; + auto getCurrentFrame() const -> QString; + auto getFileInfoModel() const -> const PAGFileInfoModel*; + auto getFrameDisplayInfoModel() const -> const PAGFrameDisplayInfoModel*; + + auto setCurrentFrame(const QString& currentFrame) -> void; + + Q_SIGNAL void totalFrameChanged(); + Q_SIGNAL void currentFrameChanged(); + Q_SIGNAL void fileInfoModelChanged(); + Q_SIGNAL void frameDisplayInfoModelChanged(); + Q_SIGNAL void dataChanged(); + + Q_SLOT void updateData(int64_t currentFrame, int64_t renderTime, int64_t presentTime, + int64_t imageDecodeTime); + + auto resetFile(const std::shared_ptr& pagFile, const std::string& filePath) -> void; + + private: + auto updateFrameDisplayInfo(int64_t renderTime, int64_t presentTime, int64_t imageDecodeTime) + -> void; + + private: + int64_t totalFrame = -1; + int64_t currentFrame = -1; + PAGFileInfoModel fileInfoModel = {}; + PAGFrameDisplayInfoModel frameDisplayInfoModel = {}; + QVector frameTimeMetricsVector = {}; +}; +} // namespace pag diff --git a/viewer/src/rendering/PAGRenderThread.cpp b/viewer/src/rendering/PAGRenderThread.cpp index 15356ea586..a50bedb9ff 100644 --- a/viewer/src/rendering/PAGRenderThread.cpp +++ b/viewer/src/rendering/PAGRenderThread.cpp @@ -26,7 +26,17 @@ PAGRenderThread::PAGRenderThread(PAGView* pagView) : pagView(pagView) { } auto PAGRenderThread::flush() -> void { + if (pagView->pagPlayer == nullptr || pagView->pagFile == nullptr) { + return; + } pagView->pagPlayer->flush(); + double progress = pagView->pagFile->getProgress(); + int64_t currentFrame = + static_cast(std::round((pagView->getTotalFrame().toDouble() - 1) * progress)); + int64_t renderingTime = pagView->pagPlayer->renderingTime(); + int64_t presentingTime = pagView->pagPlayer->presentingTime(); + int64_t imageDecodingTime = pagView->pagPlayer->imageDecodingTime(); + Q_EMIT frameTimeMetricsReady(currentFrame, renderingTime, presentingTime, imageDecodingTime); QMetaObject::invokeMethod(pagView, "update", Qt::QueuedConnection); } diff --git a/viewer/src/rendering/PAGRenderThread.h b/viewer/src/rendering/PAGRenderThread.h index f0cf51e2b1..50b24e1bdc 100644 --- a/viewer/src/rendering/PAGRenderThread.h +++ b/viewer/src/rendering/PAGRenderThread.h @@ -29,6 +29,9 @@ class PAGRenderThread : public QThread { public: explicit PAGRenderThread(PAGView* pagView); + Q_SIGNAL void frameTimeMetricsReady(int64_t frame, int64_t renderTime, int64_t presentTime, + int64_t imageDecodeTime); + Q_SLOT void flush(); Q_SLOT void shutDown(); diff --git a/viewer/src/rendering/PAGView.cpp b/viewer/src/rendering/PAGView.cpp index 969adeadaa..eb33279313 100644 --- a/viewer/src/rendering/PAGView.cpp +++ b/viewer/src/rendering/PAGView.cpp @@ -34,6 +34,12 @@ PAGView::PAGView(QQuickItem* parent) : QQuickItem(parent) { drawable->moveToThread(renderThread.get()); } +auto PAGView::flush() const -> void { + if (isPlaying_) { + QMetaObject::invokeMethod(renderThread.get(), "flush", Qt::QueuedConnection); + } +} + PAGView::~PAGView() { QMetaObject::invokeMethod(renderThread.get(), "shutDown", Qt::QueuedConnection); renderThread->wait(); @@ -41,32 +47,34 @@ PAGView::~PAGView() { auto PAGView::getPAGWidth() const -> int { if (pagFile == nullptr) { - return -1; + return 0; } return pagFile->width(); } auto PAGView::getPAGHeight() const -> int { if (pagFile == nullptr) { - return -1; + return 0; } return pagFile->height(); } -auto PAGView::getTotalFrame() const -> int { +auto PAGView::getTotalFrame() const -> QString { if (pagFile == nullptr) { - return 0; + return "0"; } - int totalFrames = static_cast(std::round(getDuration() * pagFile->frameRate() / 1000.0)); + int64_t totalFrames = + static_cast(std::round(getDuration().toLongLong() * pagFile->frameRate() / 1000.0)); if (totalFrames < 1) { totalFrames = 0; } - return totalFrames; + return QString::number(totalFrames); } -auto PAGView::getCurrentFrame() const -> int { - int totalFrames = getTotalFrame(); - return static_cast(std::round(getProgress() * (totalFrames - 1))); +auto PAGView::getCurrentFrame() const -> QString { + int64_t totalFrames = getTotalFrame().toLongLong(); + int64_t currentFrame = static_cast(std::round(getProgress() * (totalFrames - 1))); + return QString::number(currentFrame); } auto PAGView::isPlaying() const -> bool { @@ -80,11 +88,11 @@ auto PAGView::getShowVideoFrames() const -> bool { return pagPlayer->videoEnabled(); } -auto PAGView::getDuration() const -> double { +auto PAGView::getDuration() const -> QString { if (pagPlayer == nullptr) { - return 0.0; + return "0"; } - return static_cast(pagPlayer->duration()) / 1000.0; + return QString::number(pagPlayer->duration() / 1000); } auto PAGView::getProgress() const -> double { @@ -95,6 +103,16 @@ auto PAGView::getFilePath() const -> QString { return filePath; } +auto PAGView::getDisplayedTime() const -> QString { + int64_t displayedTime = + static_cast(std::round(getProgress() * getDuration().toLongLong() / 1000.0)); + int64_t displayedSeconds = displayedTime % 60; + int64_t displayedMinutes = (displayedTime / 60) % 60; + return QString("%1:%2") + .arg(displayedMinutes, 2, 10, QChar('0')) + .arg(displayedSeconds, 2, 10, QChar('0')); +} + auto PAGView::getBackgroundColor() const -> QColor { if (pagFile == nullptr) { return QColorConstants::Black; @@ -105,10 +123,6 @@ auto PAGView::getBackgroundColor() const -> QColor { } auto PAGView::getPreferredSize() const -> QSizeF { - if (pagFile == nullptr) { - return {0, 0}; - } - auto quickWindow = window(); int pagWidth = getPAGWidth(); int pagHeight = getPAGHeight(); @@ -136,9 +150,6 @@ auto PAGView::getPreferredSize() const -> QSizeF { } auto PAGView::setIsPlaying(bool isPlaying) -> void { - if (pagFile == nullptr) { - return; - } if (this->isPlaying_ == isPlaying) { return; } @@ -194,25 +205,16 @@ auto PAGView::setFile(const QString& filePath) -> bool { } auto PAGView::firstFrame() -> void { - if (pagFile == nullptr) { - return; - } setIsPlaying(false); setProgress(0); } auto PAGView::lastFrame() -> void { - if (pagFile == nullptr) { - return; - } setIsPlaying(false); setProgress(1); } auto PAGView::nextFrame() -> void { - if (pagFile == nullptr) { - return; - } setIsPlaying(false); auto progress = this->progress + progressPerFrame; if (progress > 1) { @@ -222,9 +224,6 @@ auto PAGView::nextFrame() -> void { } auto PAGView::previousFrame() -> void { - if (pagFile == nullptr) { - return; - } setIsPlaying(false); auto progress = this->progress - progressPerFrame; if (progress < 0) { @@ -274,8 +273,11 @@ QSGNode* PAGView::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData*) { } setProgress(progress); } - QMetaObject::invokeMethod(renderThread.get(), "flush", Qt::QueuedConnection); } return node; } + +auto PAGView::getRenderThread() const -> PAGRenderThread* { + return renderThread.get(); +} } // namespace pag \ No newline at end of file diff --git a/viewer/src/rendering/PAGView.h b/viewer/src/rendering/PAGView.h index 91cc00b0b5..b39312e840 100644 --- a/viewer/src/rendering/PAGView.h +++ b/viewer/src/rendering/PAGView.h @@ -34,25 +34,28 @@ class PAGView : public QQuickItem { Q_PROPERTY(int pagWidth READ getPAGWidth) Q_PROPERTY(int pagHeight READ getPAGHeight) - Q_PROPERTY(int totalFrame READ getTotalFrame) - Q_PROPERTY(int currentFrame READ getCurrentFrame) Q_PROPERTY(bool isPlaying READ isPlaying WRITE setIsPlaying NOTIFY isPlayingChanged) Q_PROPERTY(bool showVideoFrames READ getShowVideoFrames WRITE setShowVideoFrames) - Q_PROPERTY(double duration READ getDuration) Q_PROPERTY(double progress READ getProgress WRITE setProgress NOTIFY progressChanged) + Q_PROPERTY(QString totalFrame READ getTotalFrame) + Q_PROPERTY(QString currentFrame READ getCurrentFrame) + Q_PROPERTY(QString duration READ getDuration) Q_PROPERTY(QString filePath READ getFilePath NOTIFY fileChanged) + Q_PROPERTY(QString displayedTime READ getDisplayedTime) Q_PROPERTY(QColor backgroundColor READ getBackgroundColor) Q_PROPERTY(QSizeF preferredSize READ getPreferredSize) auto getPAGWidth() const -> int; auto getPAGHeight() const -> int; - auto getTotalFrame() const -> int; - auto getCurrentFrame() const -> int; + auto isPlaying() const -> bool; auto getShowVideoFrames() const -> bool; - auto getDuration() const -> double; auto getProgress() const -> double; + auto getTotalFrame() const -> QString; + auto getCurrentFrame() const -> QString; + auto getDuration() const -> QString; auto getFilePath() const -> QString; + auto getDisplayedTime() const -> QString; auto getBackgroundColor() const -> QColor; auto getPreferredSize() const -> QSizeF; @@ -65,6 +68,8 @@ class PAGView : public QQuickItem { Q_SIGNAL void fileChanged(const std::shared_ptr& pagFile, const std::string& filePath); + Q_SLOT void flush() const; + Q_INVOKABLE bool setFile(const QString& filePath); Q_INVOKABLE void firstFrame(); Q_INVOKABLE void lastFrame(); @@ -72,6 +77,7 @@ class PAGView : public QQuickItem { Q_INVOKABLE void previousFrame(); auto updatePaintNode(QSGNode*, UpdatePaintNodeData*) -> QSGNode* override; + auto getRenderThread() const -> PAGRenderThread*; private: int64_t lastPlayTime = 0; diff --git a/viewer/src/rendering/PAGWindow.cpp b/viewer/src/rendering/PAGWindow.cpp index d62c2cbd37..89245846b2 100644 --- a/viewer/src/rendering/PAGWindow.cpp +++ b/viewer/src/rendering/PAGWindow.cpp @@ -18,8 +18,9 @@ #include "PAGWindow.h" #include -#include +#include "PAGRenderThread.h" #include "PAGWindowHelper.h" +#include "profiling/PAGRunTimeModelManager.h" #include "task/PAGTaskFactory.h" namespace pag { @@ -58,13 +59,22 @@ auto PAGWindow::open() -> void { window->setPersistentGraphics(true); window->setPersistentSceneGraph(true); window->setTextRenderType(QQuickWindow::TextRenderType::NativeTextRendering); + auto surfaceFormat = window->format(); + surfaceFormat.setSwapInterval(1); + window->setFormat(surfaceFormat); pagView = window->findChild("pagView"); auto* taskFactory = window->findChild("taskFactory"); + auto* runTimeModelManager = window->findChild("runTimeModelManager"); + PAGRenderThread* renderThread = pagView->getRenderThread(); connect(window, SIGNAL(closing(QQuickCloseEvent*)), this, SLOT(onPAGViewerDestroyed()), Qt::QueuedConnection); + connect(window, &QQuickWindow::afterRendering, pagView, &PAGView::flush); connect(pagView, &PAGView::fileChanged, taskFactory, &PAGTaskFactory::resetFile); + connect(pagView, &PAGView::fileChanged, runTimeModelManager, &PAGRunTimeModelManager::resetFile); + connect(renderThread, &PAGRenderThread::frameTimeMetricsReady, runTimeModelManager, + &PAGRunTimeModelManager::updateData); } auto PAGWindow::getFilePath() -> QString { diff --git a/viewer/src/task/PAGTask.cpp b/viewer/src/task/PAGTask.cpp index 7b30fe2697..5d1b4aee33 100644 --- a/viewer/src/task/PAGTask.cpp +++ b/viewer/src/task/PAGTask.cpp @@ -18,7 +18,7 @@ #include "PAGTask.h" #include "base/utils/TimeUtil.h" -#include "utils/PAGFileUtils.h" +#include "utils/FileUtils.h" namespace pag { diff --git a/viewer/src/task/export/PAGExportAPNGTask.cpp b/viewer/src/task/export/PAGExportAPNGTask.cpp index 551ed6dbf2..bef55ec0f2 100644 --- a/viewer/src/task/export/PAGExportAPNGTask.cpp +++ b/viewer/src/task/export/PAGExportAPNGTask.cpp @@ -18,8 +18,8 @@ #include "PAGExportAPNGTask.h" #include -#include "utils/PAGFileUtils.h" -#include "utils/PAGUtils.h" +#include "utils/FileUtils.h" +#include "utils/Utils.h" namespace pag { diff --git a/viewer/src/task/export/PAGExportPNGTask.cpp b/viewer/src/task/export/PAGExportPNGTask.cpp index d5544820fb..972038580c 100644 --- a/viewer/src/task/export/PAGExportPNGTask.cpp +++ b/viewer/src/task/export/PAGExportPNGTask.cpp @@ -19,7 +19,7 @@ #include "task/export/PAGExportPNGTask.h" #include #include -#include "utils/PAGFileUtils.h" +#include "utils/FileUtils.h" namespace pag { diff --git a/viewer/src/utils/PAGFileUtils.cpp b/viewer/src/utils/FileUtils.cpp similarity index 98% rename from viewer/src/utils/PAGFileUtils.cpp rename to viewer/src/utils/FileUtils.cpp index 2ae7061d80..6ca38698fa 100644 --- a/viewer/src/utils/PAGFileUtils.cpp +++ b/viewer/src/utils/FileUtils.cpp @@ -16,7 +16,7 @@ // ///////////////////////////////////////////////////////////////////////////////////////////////// -#include "utils/PAGFileUtils.h" +#include "FileUtils.h" #include #include #include diff --git a/viewer/src/utils/PAGFileUtils.h b/viewer/src/utils/FileUtils.h similarity index 100% rename from viewer/src/utils/PAGFileUtils.h rename to viewer/src/utils/FileUtils.h diff --git a/viewer/src/utils/StringUtils.cpp b/viewer/src/utils/StringUtils.cpp new file mode 100644 index 0000000000..6b88b37df3 --- /dev/null +++ b/viewer/src/utils/StringUtils.cpp @@ -0,0 +1,88 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Tencent is pleased to support the open source community by making libpag available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// unless required by applicable law or agreed to in writing, software distributed under the +// license is distributed on an "as is" basis, without warranties or conditions of any kind, +// either express or implied. see the license for the specific language governing permissions +// and limitations under the license. +// +///////////////////////////////////////////////////////////////////////////////////////////////// + +#include "StringUtils.h" +#include + +namespace pag::Utils { + +auto toQString(double num) -> QString { + QString result; + return result.setNum(num, 'f', 2); + ; +} + +auto toQString(int32_t num) -> QString { + QString result; + return result.setNum(num); +} + +auto toQString(int64_t num) -> QString { + QString result; + return result.setNum(num); +} + +auto getMemorySizeUnit(int64_t size) -> QString { + constexpr int64_t kbThreshold = 1024; + constexpr int64_t mbThreshold = 1024 * 1024; + constexpr int64_t gbThreshold = 1024 * 1024 * 1024; + if (size < kbThreshold) { + return "B"; + } + if (size < mbThreshold) { + return "KB"; + } + if (size < gbThreshold) { + return "MB"; + } + return "GB"; +} + +auto getMemorySizeNumString(int64_t size) -> QString { + constexpr double kbThreshold = 1024; + constexpr double mbThreshold = 1024 * 1024; + constexpr double gbThreshold = 1024 * 1024 * 1024; + double dSize = static_cast(size); + if (dSize < kbThreshold) { + return toQString(size); + } + if (dSize < mbThreshold) { + return toQString(dSize / static_cast(kbThreshold)); + } + if (dSize < gbThreshold) { + return toQString(dSize / static_cast(mbThreshold)); + } + return toQString(dSize / static_cast(gbThreshold)); +} + +using TagCodeVersionPair = std::pair; +static const std::vector TagCodeVersionList = { + {pag::TagCode::FileAttributes, "1.0"}, {pag::TagCode::LayerAttributesExtra, "2.0"}, + {pag::TagCode::MosaicEffect, "3.2"}, {pag::TagCode::GradientOverlayStyle, "4.1"}, + {pag::TagCode::CameraOption, "4.2"}, {pag::TagCode::ImageScaleModes, "4.3"}}; + +auto tagCodeToVersion(uint16_t tagCode) -> std::string { + for (const auto& pair : TagCodeVersionList) { + if (tagCode <= static_cast(pair.first)) { + return pair.second; + } + } + return "Unknown"; +} + +} // namespace pag::Utils \ No newline at end of file diff --git a/viewer/src/utils/StringUtils.h b/viewer/src/utils/StringUtils.h new file mode 100644 index 0000000000..6c4bc3c5df --- /dev/null +++ b/viewer/src/utils/StringUtils.h @@ -0,0 +1,32 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Tencent is pleased to support the open source community by making libpag available. +// +// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// unless required by applicable law or agreed to in writing, software distributed under the +// license is distributed on an "as is" basis, without warranties or conditions of any kind, +// either express or implied. see the license for the specific language governing permissions +// and limitations under the license. +// +///////////////////////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include + +namespace pag::Utils { + +auto toQString(double num) -> QString; +auto toQString(int32_t num) -> QString; +auto toQString(int64_t num) -> QString; +auto getMemorySizeUnit(int64_t size) -> QString; +auto getMemorySizeNumString(int64_t size) -> QString; +auto tagCodeToVersion(uint16_t tagCode) -> std::string; + +} // namespace pag::Utils \ No newline at end of file diff --git a/viewer/src/utils/PAGUtils.cpp b/viewer/src/utils/Utils.cpp similarity index 98% rename from viewer/src/utils/PAGUtils.cpp rename to viewer/src/utils/Utils.cpp index 45d09457f0..46383a1df5 100644 --- a/viewer/src/utils/PAGUtils.cpp +++ b/viewer/src/utils/Utils.cpp @@ -16,7 +16,7 @@ // ///////////////////////////////////////////////////////////////////////////////////////////////// -#include "PAGUtils.h" +#include "Utils.h" #include "utils/apng/APNGAssembler.h" namespace pag::Utils { diff --git a/viewer/src/utils/PAGUtils.h b/viewer/src/utils/Utils.h similarity index 100% rename from viewer/src/utils/PAGUtils.h rename to viewer/src/utils/Utils.h