From e43f87552d41366ca534ef0248cbd787ce95c08b Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Mon, 11 Aug 2025 14:52:24 -0500 Subject: [PATCH] Small refactor to assign Clip and Effect ids in base class --- src/ClipBase.h | 3 +- src/IdGenerator.h | 36 ++++++++++++ src/effects/ObjectDetection.cpp | 97 +++++++++++++++++---------------- src/effects/Tracker.cpp | 13 ++++- 4 files changed, 98 insertions(+), 51 deletions(-) create mode 100644 src/IdGenerator.h diff --git a/src/ClipBase.h b/src/ClipBase.h index 4ba6b2f4..732160c1 100644 --- a/src/ClipBase.h +++ b/src/ClipBase.h @@ -16,8 +16,8 @@ #include #include "CacheMemory.h" #include "Frame.h" -#include "Point.h" #include "KeyFrame.h" +#include "IdGenerator.h" #include "Json.h" #include "TimelineBase.h" @@ -48,6 +48,7 @@ namespace openshot { public: /// Constructor for the base clip ClipBase() : + id(IdGenerator::Generate()), position(0.0), layer(0), start(0.0), diff --git a/src/IdGenerator.h b/src/IdGenerator.h new file mode 100644 index 00000000..85a10dd5 --- /dev/null +++ b/src/IdGenerator.h @@ -0,0 +1,36 @@ +/* + * @file + * @brief Header file for generating random identifier strings + */ + +// Copyright (c) 2008-2025 OpenShot Studios, LLC +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef OPENSHOT_ID_GENERATOR_H +#define OPENSHOT_ID_GENERATOR_H + +#include +#include + +namespace openshot { + + class IdGenerator { + public: + static inline std::string Generate(int length = 8) { + static const char charset[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution<> dist(0, static_cast(sizeof(charset) - 2)); + + std::string result; + result.reserve(length); + for (int i = 0; i < length; ++i) + result += charset[dist(gen)]; + return result; +} +}; + +} // namespace openshot + +#endif // OPENSHOT_ID_GENERATOR_H diff --git a/src/effects/ObjectDetection.cpp b/src/effects/ObjectDetection.cpp index 7e6c95aa..2d097160 100644 --- a/src/effects/ObjectDetection.cpp +++ b/src/effects/ObjectDetection.cpp @@ -221,16 +221,19 @@ bool ObjectDetection::LoadObjDetectdData(std::string inputFilePath) tmpObj.stroke_alpha = Keyframe(1.0); tmpObj.AddBox(frameId, x + w/2, y + h/2, w, h, 0.0); - auto ptr = std::make_shared(tmpObj); - ptr->ParentClip(this->ParentClip()); + auto ptr = std::make_shared(tmpObj); + ptr->ParentClip(this->ParentClip()); - // Prefix with effect UUID for a unique string ID - ptr->Id(this->Id() + "-" + std::to_string(objectId)); - trackedObjects.emplace(objectId, ptr); - } - } + // Prefix with effect UUID for a unique string ID + std::string prefix = this->Id(); + if (!prefix.empty()) + prefix += "-"; + ptr->Id(prefix + std::to_string(objectId)); + trackedObjects.emplace(objectId, ptr); + } + } - // Save the DetectionData for this frame + // Save the DetectionData for this frame detectionsData[frameId] = DetectionData( classIds, confidences, boxes, frameId, objectIds ); @@ -354,26 +357,26 @@ void ObjectDetection::SetJson(const std::string value) { // Load Json::Value into this object void ObjectDetection::SetJsonValue(const Json::Value root) { - // Parent properties - EffectBase::SetJsonValue(root); + // Parent properties + EffectBase::SetJsonValue(root); - // If a protobuf path is provided, load & prefix IDs - if (!root["protobuf_data_path"].isNull() && protobuf_data_path.empty()) { - protobuf_data_path = root["protobuf_data_path"].asString(); - if (!LoadObjDetectdData(protobuf_data_path)) { - throw InvalidFile("Invalid protobuf data path", ""); - } - } + // If a protobuf path is provided, load & prefix IDs + if (!root["protobuf_data_path"].isNull() && protobuf_data_path.empty()) { + protobuf_data_path = root["protobuf_data_path"].asString(); + if (!LoadObjDetectdData(protobuf_data_path)) { + throw InvalidFile("Invalid protobuf data path", ""); + } + } - // Selected index, thresholds, UI flags, filters, etc. - if (!root["selected_object_index"].isNull()) - selectedObjectIndex = root["selected_object_index"].asInt(); - if (!root["confidence_threshold"].isNull()) - confidence_threshold = root["confidence_threshold"].asFloat(); - if (!root["display_box_text"].isNull()) - display_box_text.SetJsonValue(root["display_box_text"]); - if (!root["display_boxes"].isNull()) - display_boxes.SetJsonValue(root["display_boxes"]); + // Selected index, thresholds, UI flags, filters, etc. + if (!root["selected_object_index"].isNull()) + selectedObjectIndex = root["selected_object_index"].asInt(); + if (!root["confidence_threshold"].isNull()) + confidence_threshold = root["confidence_threshold"].asFloat(); + if (!root["display_box_text"].isNull()) + display_box_text.SetJsonValue(root["display_box_text"]); + if (!root["display_boxes"].isNull()) + display_boxes.SetJsonValue(root["display_boxes"]); if (!root["class_filter"].isNull()) { class_filter = root["class_filter"].asString(); @@ -388,24 +391,24 @@ void ObjectDetection::SetJsonValue(const Json::Value root) } // Apply any per-object overrides - if (!root["objects"].isNull()) { - for (auto &kv : trackedObjects) { - auto &idx = kv.first; - auto &obj = kv.second; - std::string key = std::to_string(idx); - if (!root["objects"][key].isNull()) - obj->SetJsonValue(root["objects"][key]); - } - } - if (!root["objects_id"].isNull()) { - for (auto &kv : trackedObjects) { - auto &idx = kv.first; - auto &obj = kv.second; - Json::Value tmp; - tmp["box_id"] = root["objects_id"][idx].asString(); - obj->SetJsonValue(tmp); - } - } + if (!root["objects"].isNull()) { + for (auto &kv : trackedObjects) { + auto &idx = kv.first; + auto &obj = kv.second; + std::string key = std::to_string(idx); + if (!root["objects"][key].isNull()) + obj->SetJsonValue(root["objects"][key]); + } + } + if (!root["objects_id"].isNull()) { + for (auto &kv : trackedObjects) { + auto &idx = kv.first; + auto &obj = kv.second; + Json::Value tmp; + tmp["box_id"] = root["objects_id"][idx].asString(); + obj->SetJsonValue(tmp); + } + } } // Get all properties for a specific frame @@ -433,9 +436,9 @@ std::string ObjectDetection::PropertiesJSON(int64_t requested_frame) const { root["display_box_text"]["choices"].append(add_property_choice_json("Yes", true, display_box_text.GetValue(requested_frame))); root["display_box_text"]["choices"].append(add_property_choice_json("No", false, display_box_text.GetValue(requested_frame))); - root["display_boxes"] = add_property_json("Draw All Boxes", display_boxes.GetValue(requested_frame), "int", "", &display_boxes, 0, 1, false, requested_frame); - root["display_boxes"]["choices"].append(add_property_choice_json("Yes", true, display_boxes.GetValue(requested_frame))); - root["display_boxes"]["choices"].append(add_property_choice_json("No", false, display_boxes.GetValue(requested_frame))); + root["display_boxes"] = add_property_json("Draw All Boxes", display_boxes.GetValue(requested_frame), "int", "", &display_boxes, 0, 1, false, requested_frame); + root["display_boxes"]["choices"].append(add_property_choice_json("Yes", true, display_boxes.GetValue(requested_frame))); + root["display_boxes"]["choices"].append(add_property_choice_json("No", false, display_boxes.GetValue(requested_frame))); // Return formatted string return root.toStyledString(); diff --git a/src/effects/Tracker.cpp b/src/effects/Tracker.cpp index c9aaea21..6c6a2f50 100644 --- a/src/effects/Tracker.cpp +++ b/src/effects/Tracker.cpp @@ -46,6 +46,10 @@ Tracker::Tracker() // Seed our map with a single entry at index 0 trackedObjects.clear(); trackedObjects.emplace(0, trackedData); + + // Assign ID to the placeholder object + if (trackedData) + trackedData->Id(Id() + "-0"); } // Init effect settings @@ -222,18 +226,21 @@ void Tracker::SetJsonValue(const Json::Value root) { protobuf_data_path.clear(); } else { - // prefix “-” for each entry + // prefix "-" for each entry for (auto& kv : trackedObjects) { auto idx = kv.first; auto ptr = kv.second; if (ptr) { - ptr->Id(this->Id() + "-" + std::to_string(idx)); + std::string prefix = this->Id(); + if (!prefix.empty()) + prefix += "-"; + ptr->Id(prefix + std::to_string(idx)); } } } } - // then any per-object JSON overrides… + // then any per-object JSON overrides... if (!root["objects"].isNull()) { for (auto& kv : trackedObjects) { std::string key = std::to_string(kv.first);