From d6a707d873751de30e71af1c76fa1696cefc4c9f Mon Sep 17 00:00:00 2001 From: i-Orangeade <2930430673@qq.com> Date: Tue, 14 Oct 2025 23:11:00 +0800 Subject: [PATCH 01/11] add dynamic reset node interface --- bmf/engine/connector/include/builder.hpp | 10 +- bmf/engine/connector/src/builder.cpp | 266 ++++++++++++++++++++++ bmf/test/cpp_builder/cpp_dynamic_test.cpp | 221 ++++++++++++++++++ 3 files changed, 496 insertions(+), 1 deletion(-) create mode 100644 bmf/test/cpp_builder/cpp_dynamic_test.cpp diff --git a/bmf/engine/connector/include/builder.hpp b/bmf/engine/connector/include/builder.hpp index 0af08282..ea869b79 100644 --- a/bmf/engine/connector/include/builder.hpp +++ b/bmf/engine/connector/include/builder.hpp @@ -619,7 +619,15 @@ class BMF_ENGINE_API Graph { Graph(Graph &&rhs) = default; - private: + int update(const bmf_sdk::JsonParam& update_config); + + int dynamic_add_node(const bmf_sdk::JsonParam& node_config); + + int dynamic_remove_node(const bmf_sdk::JsonParam& node_config); + + nlohmann::json dynamic_reset_node(const bmf_sdk::JsonParam& node_config); + + private: friend class Stream; friend Node; diff --git a/bmf/engine/connector/src/builder.cpp b/bmf/engine/connector/src/builder.cpp index 60314d7c..cda3cb97 100644 --- a/bmf/engine/connector/src/builder.cpp +++ b/bmf/engine/connector/src/builder.cpp @@ -1096,6 +1096,272 @@ int Graph::FillPacket(std::string streamName, Packet packet, bool block) { return graph_->FillPacket(streamName, packet, block); } + +static inline bool check_graph_instance(const std::shared_ptr& graph_instance, const char* func_name) { + if (!graph_instance) { // 检查底层BMFGraph实例是否为空 + BMFLOG(BMF_ERROR) << "[builder::Graph::" << func_name << "] BMFGraph instance not initialized"; + return false; + } + return true; +} + +// ----------------- update ----------------- +int Graph::update(const bmf_sdk::JsonParam& update_config) { + if (!check_graph_instance(graph_->graphInstance_, "update")) { + return -1; + } + + try { + JsonParam new_update_config = update_config; + + if (new_update_config.json_value_.contains("nodes") && + new_update_config.json_value_["nodes"].is_array()) { + + auto& nodes = new_update_config.json_value_["nodes"]; + for (auto& node : nodes) { + std::shared_ptr matched_node = nullptr; + + // 1. 补全 reset 节点 id(通过 alias 查找原节点) + if ((!node.contains("id") || node["id"].is_null()) && + node.contains("action") && node["action"] == "reset" && + node.contains("alias")) { + + std::string alias = node["alias"].get(); + bool found = false; + for (auto &real_node : graph_->nodes_) { + if (real_node && real_node->alias_ == alias) { + node["id"] = real_node->id_; + BMFLOG(BMF_INFO) << "[update] reset 节点通过 alias 匹配补全 id: alias=" + << alias << " id=" << real_node->id_; + found = true; + matched_node = real_node; + break; + } + } + if (!found) { + BMFLOG(BMF_ERROR) << "[update] 找不到 alias 对应的节点: " << alias; + continue; + } + } + + // 2. 校验 id + if (!node.contains("id")) { + BMFLOG(BMF_ERROR) << "[update] 节点缺少 id,跳过"; + continue; + } + int node_id = node["id"].get(); + + // 3. 查找原节点 + std::shared_ptr real_node = matched_node; + if (!real_node) { + for (auto &n : graph_->nodes_) { + if (n && n->id_ == node_id) { + real_node = n; + break; + } + } + } + if (!real_node) { + BMFLOG(BMF_ERROR) << "[update] 找不到 id 对应节点: " << node_id; + continue; + } + + // 4. 补全 module_info + if (!node.contains("module_info") || !node["module_info"].is_object()) { + auto& module = real_node->moduleInfo_; + std::string module_type_str; + switch (module.moduleType_) { + case CPP: module_type_str = "c++"; break; + case Python: module_type_str = "python"; break; + case C: module_type_str = "c"; break; + case Go: module_type_str = "go"; break; + default: module_type_str = ""; + } + node["module_info"] = nlohmann::json({ + {"name", module.moduleName_}, + {"type", module_type_str}, + {"path", module.modulePath_}, + {"entry", module.moduleEntry_} + }); + BMFLOG(BMF_INFO) << "[update] 补全 module_info: node_id=" << node_id + << " name=" << module.moduleName_; + } + + // 5. 补全 input_manager + if (!node.contains("input_manager") || !node["input_manager"].is_string()) { + std::string im_str; + switch (real_node->inputManager_) { + case Immediate: im_str = "immediate"; break; + case Default: im_str = "default"; break; + case Server: im_str = "server"; break; + default: im_str = "default"; + } + node["input_manager"] = im_str; + BMFLOG(BMF_INFO) << "[update] 补全 input_manager: node_id=" << node_id + << " type=" << im_str; + } + + // 6. 补全 scheduler + if (!node.contains("scheduler") || !node["scheduler"].is_number()) { + node["scheduler"] = real_node->scheduler_; + BMFLOG(BMF_INFO) << "[update] 补全 scheduler: node_id=" << node_id + << " value=" << real_node->scheduler_; + } + + // 7. 确保 option 是对象 + if (!node.contains("option") || !node["option"].is_object()) { + node["option"] = nlohmann::json::object(); + BMFLOG(BMF_INFO) << "[update] 初始化 option: node_id=" << node_id; + } + } + } + + std::string config_str = new_update_config.json_value_.dump(); + BMFLOG(BMF_INFO) << "[update] 底层配置(原始 JSON): " << config_str; + + // 调用底层 update + graph_->graphInstance_->update(config_str, false); + BMFLOG(BMF_INFO) << "[update] 成功"; + + return 0; + } catch (const std::exception& e) { + BMFLOG(BMF_ERROR) << "[update] 异常: " << e.what(); + return -1; + } +} + +// 动态添加节点 +int Graph::dynamic_add_node(const bmf_sdk::JsonParam& node_config) { + try { + // 1. 提取节点配置 + JsonParam update_cfg; + nlohmann::json target_node; + if (node_config.json_value_.contains("nodes") && + node_config.json_value_["nodes"].is_array()) { + target_node = node_config.json_value_["nodes"][0]; + } else { + target_node = node_config.json_value_; + } + + // 2. 补全必填字段 + if (!target_node.contains("action")) target_node["action"] = "add"; + if (!target_node.contains("scheduler")) target_node["scheduler"] = 0; + if (!target_node.contains("input_manager")) target_node["input_manager"] = "immediate"; + + if (!target_node.contains("meta_info") || !target_node["meta_info"].is_object()) { + target_node["meta_info"] = nlohmann::json({ + {"premodule_id", -1}, + {"callback_binding", nlohmann::json::array()}, + {"queue_length_limit", 5} + }); + } + + if (!target_node.contains("module_info") || !target_node["module_info"].is_object()) { + target_node["module_info"] = nlohmann::json({ + {"name", "c_ffmpeg_filter"}, + {"type", "c++"}, + {"path", "/root/bmf/output/bmf/lib/libbuiltin_modules.so"}, + {"entry", ""} + }); + } + + if (target_node.contains("output_streams") && + target_node["output_streams"].is_array()) { + for (auto& os : target_node["output_streams"]) { + if (!os.contains("identifier")) { + os["identifier"] = "c_ffmpeg_filter_" + + std::to_string(target_node.value("id", 0)) + "_0"; + } + } + } + + // 3. 构造 update 配置 + update_cfg.json_value_["nodes"] = nlohmann::json::array({target_node}); + update_cfg.json_value_["option"] = nlohmann::json::object(); + + BMFLOG(BMF_INFO) << "[dynamic_add_node] 调用 update 配置:\n" + << update_cfg.json_value_.dump(4); + + return update(update_cfg); + + } catch (const std::exception& e) { + BMFLOG(BMF_ERROR) << "[dynamic_add_node] 异常: " << e.what(); + return -1; + } +} + + +// ----------------- 动态删除节点 ----------------- +int Graph::dynamic_remove_node(const bmf_sdk::JsonParam& node_config) { + try { + // 1. 基础校验 + if (!node_config.json_value_.is_object() || + (!node_config.json_value_.contains("id") && + !node_config.json_value_.contains("alias"))) { + BMFLOG(BMF_ERROR) << "[dynamic_remove_node] 缺少 id 或 alias"; + return -1; + } + + // 2. 构造删除配置 + JsonParam update_cfg; + update_cfg.json_value_["nodes"] = + nlohmann::json::array({node_config.json_value_}); + update_cfg.json_value_["nodes"][0]["action"] = "remove"; + update_cfg.json_value_["option"] = nlohmann::json::object(); + + // 3. 调用 update + BMFLOG(BMF_INFO) << "[dynamic_remove_node] 调用 update 配置:\n" + << update_cfg.json_value_.dump(4); + + return update(update_cfg); + + } catch (const std::exception& e) { + BMFLOG(BMF_ERROR) << "[dynamic_remove_node] 异常: " << e.what(); + return -1; + } +} + + +// ----------------- 动态重置节点 ----------------- +nlohmann::json Graph::dynamic_reset_node(const bmf_sdk::JsonParam &node_config) { + try { + // 1. 校验必要字段:仅需 alias 或 id(与 Python 一致) + if (!node_config.json_value_.is_object() || + (!node_config.json_value_.contains("alias") && + !node_config.json_value_.contains("id"))) { + BMFLOG(BMF_ERROR) << "[dynamic_reset_node] 配置无效,缺少 alias 或 id"; + return nlohmann::json(); + } + + // 2. 构造单个 reset 节点配置 + nlohmann::json node_json; + node_json["action"] = "reset"; // 标记重置动作 + + // 传递 alias 或 id + if (node_config.json_value_.contains("alias")) + node_json["alias"] = node_config.json_value_["alias"]; + if (node_config.json_value_.contains("id")) + node_json["id"] = node_config.json_value_["id"]; + + nlohmann::json option_json = node_config.json_value_; + option_json.erase("alias"); + option_json.erase("id"); + node_json["option"] = option_json; + + // 构造最终 update 配置,保证 nodes 字段存在 + nlohmann::json update_config; + update_config["nodes"] = nlohmann::json::array({node_json}); + + BMFLOG(BMF_INFO) << "[dynamic_reset_node] 生成重置配置:\n" << update_config.dump(2); + return update_config; + + } catch (const std::exception &e) { + BMFLOG(BMF_ERROR) << "[dynamic_reset_node] 异常: " << e.what(); + return nlohmann::json(); + } +} + + void SyncPackets::Insert(int streamId, std::vector frames) { packets.insert(std::make_pair(streamId, frames)); } diff --git a/bmf/test/cpp_builder/cpp_dynamic_test.cpp b/bmf/test/cpp_builder/cpp_dynamic_test.cpp new file mode 100644 index 00000000..6810b7b0 --- /dev/null +++ b/bmf/test/cpp_builder/cpp_dynamic_test.cpp @@ -0,0 +1,221 @@ +#include +#include +#include "gtest/gtest.h" +#include +#include +#include "../include/common.h" +#include "../../connector/include/builder.hpp" +#include "cpp_test_helper.h" + +// 动态重置功能测试 +TEST(cpp_dynamic_reset, reset_pass_through_node) { + const std::string output_file = "./output_reset_cpp.mp4"; + const std::string input_file = "../../files/big_bunny_10s_30fps.mp4"; + BMF_CPP_FILE_REMOVE(output_file); + + // 1. 创建主图 + nlohmann::json graph_para = {{"dump_graph", 1}}; + auto main_graph = bmf::builder::Graph(bmf::builder::NormalMode, + bmf_sdk::JsonParam(graph_para)); + BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 主图创建完成"; + + // 3. 添加解码器节点 + nlohmann::json decode_para = { + {"input_path", input_file} + }; + auto decoder_node = main_graph.Decode(bmf_sdk::JsonParam(decode_para), + "decoder0"); // 第二个参数是节点别名 + auto video_stream = decoder_node["video"]; // 提取视频流 + auto audio_stream = decoder_node["audio"]; // 提取音频流 + BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 解码器节点创建完成:alias=decoder0"; + + // 3. 添加待重置 PassThrough 节点 + std::vector pass_through_inputs = {video_stream, audio_stream}; + nlohmann::json pass_through_para = {}; + bmf_sdk::JsonParam pass_through_option(nlohmann::json::object()); + const std::string python_module_dir = "../../../bmf/test/dynamical_graph"; + auto pass_through_node = main_graph.Module( + pass_through_inputs, + "reset_pass_through", + bmf::builder::ModuleType::Python, + pass_through_option, + "reset_pass_through", + python_module_dir, + "", + bmf::builder::InputManagerType::Immediate, + 0 + ); + BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 待重置节点创建完成"; + + // 5. 非阻塞启动图(对应 Python 层 run_wo_block,匹配 Graph::Start API) + main_graph.Start(true, true); // 参数1:dump_graph(true=打印图配置),参数2:needMerge(true=合并配置) + BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 图非阻塞启动,等待20ms确保节点初始化"; + std::this_thread::sleep_for(std::chrono::milliseconds(20)); + + // 5. 构造动态重置配置 + nlohmann::json reset_config = { + {"alias", "reset_pass_through"}, + {"output_path", output_file}, + {"video_params", { + {"codec", "h264"}, + {"width", 320}, + {"height", 240}, + {"crf", 23}, + {"preset", "veryfast"} + }} + }; + bmf_sdk::JsonParam reset_config_param(reset_config); + BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 动态重置配置:\n" << reset_config.dump(2); + + nlohmann::json reset_update_config = main_graph.dynamic_reset_node(reset_config_param); + if (reset_update_config.is_null()) { + BMFLOG(BMF_ERROR) << "[cpp_dynamic_reset] 动态重置配置生成失败"; + FAIL() << "动态重置配置生成失败"; + } + + // 执行实际的更新操作 + int update_ret = main_graph.update(bmf_sdk::JsonParam(reset_update_config)); + if (update_ret != 0) { + BMFLOG(BMF_ERROR) << "[cpp_dynamic_reset] 动态重置调用失败,返回码:" << update_ret; + FAIL() << "动态重置节点调用失败"; + } + + BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 动态重置指令已发送,等待1秒确保处理完成"; + std::this_thread::sleep_for(std::chrono::seconds(1)); + + // 8. 关闭图(释放资源,匹配 Graph::Close API) + int close_ret = main_graph.Close(); + if (close_ret != 0) { + BMFLOG(BMF_ERROR) << "[cpp_dynamic_reset] 图关闭失败,返回码:" << close_ret; + FAIL() << "图关闭失败"; + } + BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 主图已正常关闭"; + + BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 测试通过:动态重置功能正常,输出文件符合预期"; +} + +// 动态添加功能测试 +TEST(cpp_dynamic_add, add_decoder_and_encoder_only) { + // 1. 路径配置 + const std::string input_file = "../../files/big_bunny_10s_30fps.mp4"; + const std::string input_file2 = "../../files/big_bunny_10s_30fps.mp4"; + const std::string output_file = "./output.mp4"; + BMF_CPP_FILE_REMOVE(output_file); + + // 2. 创建主图 + nlohmann::json graph_para = {{"dump_graph", 1}}; + auto main_graph = bmf::builder::Graph(bmf::builder::NormalMode, + bmf_sdk::JsonParam(graph_para)); + BMFLOG(BMF_INFO) << "[cpp_dynamic_add] 主图创建完成"; + + // 3. 添加解码器节点 + nlohmann::json decode_para = { + {"input_path", input_file}, + {"alias", "decoder"} + }; + auto decoder_node = main_graph.Decode(bmf_sdk::JsonParam(decode_para), + "decoder0"); + auto video_stream = decoder_node["video"]; + auto audio_stream = decoder_node["audio"]; + BMFLOG(BMF_INFO) << "[cpp_dynamic_add] 解码器节点创建完成:alias=decoder0"; + + std::vector pass_through_inputs; + // 4.Graph::Module + bmf_sdk::JsonParam pass_through_option(nlohmann::json::object()); + + auto pass_through_node = main_graph.Module( + pass_through_inputs, + "pass_through", + bmf::builder::ModuleType::CPP, + pass_through_option, + "pass_through", + "", + "", + bmf::builder::InputManagerType::Immediate, + 0 + ); + BMFLOG(BMF_INFO) << "[cpp_dynamic_add] pass_through模块创建完成"; + + // 5. 非阻塞启动图 + main_graph.Start(true, true); + BMFLOG(BMF_INFO) << "[cpp_dynamic_add] 主图非阻塞启动"; + std::this_thread::sleep_for(std::chrono::milliseconds(20)); + + // 构造decoder1的动态配置 + nlohmann::json decoder1_config = { + {"alias", "decoder1"}, + {"module_info", { + {"name", "c_ffmpeg_decoder"}, + {"type", "c++"} + }}, + {"option", { + {"input_path", input_file2}, + {"alias", "decoder1"} + }}, + {"output_streams", nlohmann::json::array({ + {{"identifier", "pass_through.0_0"}, {"alias", "video"}}, + {{"identifier", "pass_through.0_1"}, {"alias", "audio"}} + })}, + {"input_manager", "immediate"}, + {"scheduler", 0} + }; + // 调用dynamic_add_node + bmf_sdk::JsonParam decoder1_param(decoder1_config); + int add_decoder_ret = main_graph.dynamic_add_node(decoder1_param); + if (add_decoder_ret != 0) { + BMFLOG(BMF_ERROR) << "[cpp_dynamic_add] decoder1添加失败,返回码:" << add_decoder_ret; + FAIL() << "decoder1添加失败"; + } + BMFLOG(BMF_INFO) << "[cpp_dynamic_add] decoder1动态添加完成"; + std::this_thread::sleep_for(std::chrono::milliseconds(30)); + + + // 7. 动态添加encoder1 + nlohmann::json encoder1_config = { + {"alias", "encoder1"}, + {"module_info", { + {"name", "c_ffmpeg_encoder"}, + {"type", "c++"} + }}, + {"option", { + {"output_path", output_file}, + {"alias", "encoder1"} + }}, + {"input_streams", nlohmann::json::array({ + {{"identifier", "pass_through.1_0"}, {"alias", "video"}}, + {{"identifier", "pass_through.1_1"}, {"alias", "audio"}} + })}, + {"input_manager", "immediate"}, + {"scheduler", 1} + }; + // 调用dynamic_add_node添加编码器 + bmf_sdk::JsonParam encoder1_param(encoder1_config); + int add_encoder_ret = main_graph.dynamic_add_node(encoder1_param); + if (add_encoder_ret != 0) { + BMFLOG(BMF_ERROR) << "[cpp_dynamic_add] encoder1添加失败,返回码:" << add_encoder_ret; + FAIL() << "encoder1添加失败"; + } + BMFLOG(BMF_INFO) << "[cpp_dynamic_add] encoder1动态添加完成)"; + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + + + BMFLOG(BMF_INFO) << "[cpp_dynamic_add] 等待编码完成"; + std::this_thread::sleep_for(std::chrono::seconds(2)); + + // 8. 关闭图 + int close_ret = main_graph.Close(); + if (close_ret != 0) { + BMFLOG(BMF_ERROR) << "[cpp_dynamic_add] 图关闭失败,返回码:" << close_ret; + FAIL() << "图关闭失败"; + } + BMFLOG(BMF_INFO) << "[cpp_dynamic_add] 主图已正常关闭"; + + BMFLOG(BMF_INFO) << "[cpp_dynamic_add] 测试通过:动态添加功能正常"; +} + + +// 测试入口(默认GTest入口) +int main(int argc, char **argv) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file From 409c1a49dfc3b9a110faf4f9bf1af37260e1df8a Mon Sep 17 00:00:00 2001 From: i-Orangeade <2930430673@qq.com> Date: Sun, 19 Oct 2025 14:40:57 +0800 Subject: [PATCH 02/11] reduce reset and update interfaces --- bmf/engine/connector/include/builder.hpp | 9 +- bmf/engine/connector/src/builder.cpp | 155 +++------------------- bmf/test/cpp_builder/cpp_dynamic_test.cpp | 14 +- 3 files changed, 33 insertions(+), 145 deletions(-) diff --git a/bmf/engine/connector/include/builder.hpp b/bmf/engine/connector/include/builder.hpp index ea869b79..a3225cd3 100644 --- a/bmf/engine/connector/include/builder.hpp +++ b/bmf/engine/connector/include/builder.hpp @@ -619,13 +619,14 @@ class BMF_ENGINE_API Graph { Graph(Graph &&rhs) = default; - int update(const bmf_sdk::JsonParam& update_config); + int Update(const bmf_sdk::JsonParam& update_config); - int dynamic_add_node(const bmf_sdk::JsonParam& node_config); + int DynamicAddNode(const bmf_sdk::JsonParam& node_config); - int dynamic_remove_node(const bmf_sdk::JsonParam& node_config); + int DynamicRemoveNode(const bmf_sdk::JsonParam& node_config); + + nlohmann::json DynamicResetNode(const bmf_sdk::JsonParam& node_config); - nlohmann::json dynamic_reset_node(const bmf_sdk::JsonParam& node_config); private: friend class Stream; diff --git a/bmf/engine/connector/src/builder.cpp b/bmf/engine/connector/src/builder.cpp index cda3cb97..5f4450ef 100644 --- a/bmf/engine/connector/src/builder.cpp +++ b/bmf/engine/connector/src/builder.cpp @@ -1106,132 +1106,26 @@ static inline bool check_graph_instance(const std::shared_ptr& gr } // ----------------- update ----------------- -int Graph::update(const bmf_sdk::JsonParam& update_config) { - if (!check_graph_instance(graph_->graphInstance_, "update")) { - return -1; - } - +int Graph::Update(const bmf_sdk::JsonParam& update_config) { try { - JsonParam new_update_config = update_config; - - if (new_update_config.json_value_.contains("nodes") && - new_update_config.json_value_["nodes"].is_array()) { - - auto& nodes = new_update_config.json_value_["nodes"]; - for (auto& node : nodes) { - std::shared_ptr matched_node = nullptr; - - // 1. 补全 reset 节点 id(通过 alias 查找原节点) - if ((!node.contains("id") || node["id"].is_null()) && - node.contains("action") && node["action"] == "reset" && - node.contains("alias")) { - - std::string alias = node["alias"].get(); - bool found = false; - for (auto &real_node : graph_->nodes_) { - if (real_node && real_node->alias_ == alias) { - node["id"] = real_node->id_; - BMFLOG(BMF_INFO) << "[update] reset 节点通过 alias 匹配补全 id: alias=" - << alias << " id=" << real_node->id_; - found = true; - matched_node = real_node; - break; - } - } - if (!found) { - BMFLOG(BMF_ERROR) << "[update] 找不到 alias 对应的节点: " << alias; - continue; - } - } - - // 2. 校验 id - if (!node.contains("id")) { - BMFLOG(BMF_ERROR) << "[update] 节点缺少 id,跳过"; - continue; - } - int node_id = node["id"].get(); - - // 3. 查找原节点 - std::shared_ptr real_node = matched_node; - if (!real_node) { - for (auto &n : graph_->nodes_) { - if (n && n->id_ == node_id) { - real_node = n; - break; - } - } - } - if (!real_node) { - BMFLOG(BMF_ERROR) << "[update] 找不到 id 对应节点: " << node_id; - continue; - } - - // 4. 补全 module_info - if (!node.contains("module_info") || !node["module_info"].is_object()) { - auto& module = real_node->moduleInfo_; - std::string module_type_str; - switch (module.moduleType_) { - case CPP: module_type_str = "c++"; break; - case Python: module_type_str = "python"; break; - case C: module_type_str = "c"; break; - case Go: module_type_str = "go"; break; - default: module_type_str = ""; - } - node["module_info"] = nlohmann::json({ - {"name", module.moduleName_}, - {"type", module_type_str}, - {"path", module.modulePath_}, - {"entry", module.moduleEntry_} - }); - BMFLOG(BMF_INFO) << "[update] 补全 module_info: node_id=" << node_id - << " name=" << module.moduleName_; - } - - // 5. 补全 input_manager - if (!node.contains("input_manager") || !node["input_manager"].is_string()) { - std::string im_str; - switch (real_node->inputManager_) { - case Immediate: im_str = "immediate"; break; - case Default: im_str = "default"; break; - case Server: im_str = "server"; break; - default: im_str = "default"; - } - node["input_manager"] = im_str; - BMFLOG(BMF_INFO) << "[update] 补全 input_manager: node_id=" << node_id - << " type=" << im_str; - } - - // 6. 补全 scheduler - if (!node.contains("scheduler") || !node["scheduler"].is_number()) { - node["scheduler"] = real_node->scheduler_; - BMFLOG(BMF_INFO) << "[update] 补全 scheduler: node_id=" << node_id - << " value=" << real_node->scheduler_; - } - - // 7. 确保 option 是对象 - if (!node.contains("option") || !node["option"].is_object()) { - node["option"] = nlohmann::json::object(); - BMFLOG(BMF_INFO) << "[update] 初始化 option: node_id=" << node_id; - } - } - } - - std::string config_str = new_update_config.json_value_.dump(); - BMFLOG(BMF_INFO) << "[update] 底层配置(原始 JSON): " << config_str; + // 直接传递配置给engine层 + std::string config_str = update_config.json_value_.dump(); + BMFLOG(BMF_INFO) << "[Update] 底层配置(原始 JSON): " << config_str; // 调用底层 update graph_->graphInstance_->update(config_str, false); - BMFLOG(BMF_INFO) << "[update] 成功"; + BMFLOG(BMF_INFO) << "[Update] 成功"; return 0; } catch (const std::exception& e) { - BMFLOG(BMF_ERROR) << "[update] 异常: " << e.what(); + BMFLOG(BMF_ERROR) << "[Update] 异常: " << e.what(); return -1; } } + // 动态添加节点 -int Graph::dynamic_add_node(const bmf_sdk::JsonParam& node_config) { +int Graph::DynamicAddNode(const bmf_sdk::JsonParam& node_config) { try { // 1. 提取节点配置 JsonParam update_cfg; @@ -1282,7 +1176,7 @@ int Graph::dynamic_add_node(const bmf_sdk::JsonParam& node_config) { BMFLOG(BMF_INFO) << "[dynamic_add_node] 调用 update 配置:\n" << update_cfg.json_value_.dump(4); - return update(update_cfg); + return Update(update_cfg); } catch (const std::exception& e) { BMFLOG(BMF_ERROR) << "[dynamic_add_node] 异常: " << e.what(); @@ -1292,7 +1186,7 @@ int Graph::dynamic_add_node(const bmf_sdk::JsonParam& node_config) { // ----------------- 动态删除节点 ----------------- -int Graph::dynamic_remove_node(const bmf_sdk::JsonParam& node_config) { +int Graph::DynamicRemoveNode(const bmf_sdk::JsonParam& node_config) { try { // 1. 基础校验 if (!node_config.json_value_.is_object() || @@ -1313,7 +1207,7 @@ int Graph::dynamic_remove_node(const bmf_sdk::JsonParam& node_config) { BMFLOG(BMF_INFO) << "[dynamic_remove_node] 调用 update 配置:\n" << update_cfg.json_value_.dump(4); - return update(update_cfg); + return Update(update_cfg); } catch (const std::exception& e) { BMFLOG(BMF_ERROR) << "[dynamic_remove_node] 异常: " << e.what(); @@ -1323,40 +1217,33 @@ int Graph::dynamic_remove_node(const bmf_sdk::JsonParam& node_config) { // ----------------- 动态重置节点 ----------------- -nlohmann::json Graph::dynamic_reset_node(const bmf_sdk::JsonParam &node_config) { +nlohmann::json Graph::DynamicResetNode(const bmf_sdk::JsonParam &node_config) { try { - // 1. 校验必要字段:仅需 alias 或 id(与 Python 一致) + // 1. 校验必要字段:只需要 alias if (!node_config.json_value_.is_object() || - (!node_config.json_value_.contains("alias") && - !node_config.json_value_.contains("id"))) { - BMFLOG(BMF_ERROR) << "[dynamic_reset_node] 配置无效,缺少 alias 或 id"; + !node_config.json_value_.contains("alias")) { + BMFLOG(BMF_ERROR) << "[DynamicResetNode] 配置无效,缺少 alias"; return nlohmann::json(); } - // 2. 构造单个 reset 节点配置 + // 2. 构造极简的 reset 节点配置 nlohmann::json node_json; - node_json["action"] = "reset"; // 标记重置动作 - - // 传递 alias 或 id - if (node_config.json_value_.contains("alias")) - node_json["alias"] = node_config.json_value_["alias"]; - if (node_config.json_value_.contains("id")) - node_json["id"] = node_config.json_value_["id"]; + node_json["action"] = "reset"; + node_json["alias"] = node_config.json_value_["alias"]; nlohmann::json option_json = node_config.json_value_; option_json.erase("alias"); - option_json.erase("id"); node_json["option"] = option_json; - // 构造最终 update 配置,保证 nodes 字段存在 + // 构造最终 update 配置 nlohmann::json update_config; update_config["nodes"] = nlohmann::json::array({node_json}); - BMFLOG(BMF_INFO) << "[dynamic_reset_node] 生成重置配置:\n" << update_config.dump(2); + BMFLOG(BMF_INFO) << "[DynamicResetNode] 生成重置配置:\n" << update_config.dump(2); return update_config; } catch (const std::exception &e) { - BMFLOG(BMF_ERROR) << "[dynamic_reset_node] 异常: " << e.what(); + BMFLOG(BMF_ERROR) << "[DynamicResetNode] 异常: " << e.what(); return nlohmann::json(); } } diff --git a/bmf/test/cpp_builder/cpp_dynamic_test.cpp b/bmf/test/cpp_builder/cpp_dynamic_test.cpp index 6810b7b0..61d25109 100644 --- a/bmf/test/cpp_builder/cpp_dynamic_test.cpp +++ b/bmf/test/cpp_builder/cpp_dynamic_test.cpp @@ -47,7 +47,7 @@ TEST(cpp_dynamic_reset, reset_pass_through_node) { ); BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 待重置节点创建完成"; - // 5. 非阻塞启动图(对应 Python 层 run_wo_block,匹配 Graph::Start API) + // 4. 非阻塞启动图(对应 Python 层 run_wo_block,匹配 Graph::Start API) main_graph.Start(true, true); // 参数1:dump_graph(true=打印图配置),参数2:needMerge(true=合并配置) BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 图非阻塞启动,等待20ms确保节点初始化"; std::this_thread::sleep_for(std::chrono::milliseconds(20)); @@ -67,14 +67,14 @@ TEST(cpp_dynamic_reset, reset_pass_through_node) { bmf_sdk::JsonParam reset_config_param(reset_config); BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 动态重置配置:\n" << reset_config.dump(2); - nlohmann::json reset_update_config = main_graph.dynamic_reset_node(reset_config_param); + nlohmann::json reset_update_config = main_graph.DynamicResetNode(reset_config_param); if (reset_update_config.is_null()) { BMFLOG(BMF_ERROR) << "[cpp_dynamic_reset] 动态重置配置生成失败"; FAIL() << "动态重置配置生成失败"; } // 执行实际的更新操作 - int update_ret = main_graph.update(bmf_sdk::JsonParam(reset_update_config)); + int update_ret = main_graph.Update(bmf_sdk::JsonParam(reset_update_config)); if (update_ret != 0) { BMFLOG(BMF_ERROR) << "[cpp_dynamic_reset] 动态重置调用失败,返回码:" << update_ret; FAIL() << "动态重置节点调用失败"; @@ -83,7 +83,7 @@ TEST(cpp_dynamic_reset, reset_pass_through_node) { BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 动态重置指令已发送,等待1秒确保处理完成"; std::this_thread::sleep_for(std::chrono::seconds(1)); - // 8. 关闭图(释放资源,匹配 Graph::Close API) + // 6. 关闭图(释放资源,匹配 Graph::Close API) int close_ret = main_graph.Close(); if (close_ret != 0) { BMFLOG(BMF_ERROR) << "[cpp_dynamic_reset] 图关闭失败,返回码:" << close_ret; @@ -161,7 +161,7 @@ TEST(cpp_dynamic_add, add_decoder_and_encoder_only) { }; // 调用dynamic_add_node bmf_sdk::JsonParam decoder1_param(decoder1_config); - int add_decoder_ret = main_graph.dynamic_add_node(decoder1_param); + int add_decoder_ret = main_graph.DynamicAddNode(decoder1_param); if (add_decoder_ret != 0) { BMFLOG(BMF_ERROR) << "[cpp_dynamic_add] decoder1添加失败,返回码:" << add_decoder_ret; FAIL() << "decoder1添加失败"; @@ -190,12 +190,12 @@ TEST(cpp_dynamic_add, add_decoder_and_encoder_only) { }; // 调用dynamic_add_node添加编码器 bmf_sdk::JsonParam encoder1_param(encoder1_config); - int add_encoder_ret = main_graph.dynamic_add_node(encoder1_param); + int add_encoder_ret = main_graph.DynamicAddNode(encoder1_param); if (add_encoder_ret != 0) { BMFLOG(BMF_ERROR) << "[cpp_dynamic_add] encoder1添加失败,返回码:" << add_encoder_ret; FAIL() << "encoder1添加失败"; } - BMFLOG(BMF_INFO) << "[cpp_dynamic_add] encoder1动态添加完成)"; + BMFLOG(BMF_INFO) << "[cpp_dynamic_add] encoder1动态添加完成"; std::this_thread::sleep_for(std::chrono::milliseconds(50)); From d016620a3b52f67d93bca4b96b5e64ff23e62692 Mon Sep 17 00:00:00 2001 From: i-Orangeade <2930430673@qq.com> Date: Sun, 19 Oct 2025 15:47:58 +0800 Subject: [PATCH 03/11] delete lrrelevant code --- bmf/engine/connector/include/builder.hpp | 4 - bmf/engine/connector/src/builder.cpp | 99 ------------------ bmf/test/cpp_builder/cpp_dynamic_test.cpp | 119 ---------------------- 3 files changed, 222 deletions(-) diff --git a/bmf/engine/connector/include/builder.hpp b/bmf/engine/connector/include/builder.hpp index a3225cd3..9e764cef 100644 --- a/bmf/engine/connector/include/builder.hpp +++ b/bmf/engine/connector/include/builder.hpp @@ -621,10 +621,6 @@ class BMF_ENGINE_API Graph { int Update(const bmf_sdk::JsonParam& update_config); - int DynamicAddNode(const bmf_sdk::JsonParam& node_config); - - int DynamicRemoveNode(const bmf_sdk::JsonParam& node_config); - nlohmann::json DynamicResetNode(const bmf_sdk::JsonParam& node_config); diff --git a/bmf/engine/connector/src/builder.cpp b/bmf/engine/connector/src/builder.cpp index 5f4450ef..d821ab3c 100644 --- a/bmf/engine/connector/src/builder.cpp +++ b/bmf/engine/connector/src/builder.cpp @@ -1097,13 +1097,6 @@ int Graph::FillPacket(std::string streamName, Packet packet, bool block) { } -static inline bool check_graph_instance(const std::shared_ptr& graph_instance, const char* func_name) { - if (!graph_instance) { // 检查底层BMFGraph实例是否为空 - BMFLOG(BMF_ERROR) << "[builder::Graph::" << func_name << "] BMFGraph instance not initialized"; - return false; - } - return true; -} // ----------------- update ----------------- int Graph::Update(const bmf_sdk::JsonParam& update_config) { @@ -1124,98 +1117,6 @@ int Graph::Update(const bmf_sdk::JsonParam& update_config) { } -// 动态添加节点 -int Graph::DynamicAddNode(const bmf_sdk::JsonParam& node_config) { - try { - // 1. 提取节点配置 - JsonParam update_cfg; - nlohmann::json target_node; - if (node_config.json_value_.contains("nodes") && - node_config.json_value_["nodes"].is_array()) { - target_node = node_config.json_value_["nodes"][0]; - } else { - target_node = node_config.json_value_; - } - - // 2. 补全必填字段 - if (!target_node.contains("action")) target_node["action"] = "add"; - if (!target_node.contains("scheduler")) target_node["scheduler"] = 0; - if (!target_node.contains("input_manager")) target_node["input_manager"] = "immediate"; - - if (!target_node.contains("meta_info") || !target_node["meta_info"].is_object()) { - target_node["meta_info"] = nlohmann::json({ - {"premodule_id", -1}, - {"callback_binding", nlohmann::json::array()}, - {"queue_length_limit", 5} - }); - } - - if (!target_node.contains("module_info") || !target_node["module_info"].is_object()) { - target_node["module_info"] = nlohmann::json({ - {"name", "c_ffmpeg_filter"}, - {"type", "c++"}, - {"path", "/root/bmf/output/bmf/lib/libbuiltin_modules.so"}, - {"entry", ""} - }); - } - - if (target_node.contains("output_streams") && - target_node["output_streams"].is_array()) { - for (auto& os : target_node["output_streams"]) { - if (!os.contains("identifier")) { - os["identifier"] = "c_ffmpeg_filter_" + - std::to_string(target_node.value("id", 0)) + "_0"; - } - } - } - - // 3. 构造 update 配置 - update_cfg.json_value_["nodes"] = nlohmann::json::array({target_node}); - update_cfg.json_value_["option"] = nlohmann::json::object(); - - BMFLOG(BMF_INFO) << "[dynamic_add_node] 调用 update 配置:\n" - << update_cfg.json_value_.dump(4); - - return Update(update_cfg); - - } catch (const std::exception& e) { - BMFLOG(BMF_ERROR) << "[dynamic_add_node] 异常: " << e.what(); - return -1; - } -} - - -// ----------------- 动态删除节点 ----------------- -int Graph::DynamicRemoveNode(const bmf_sdk::JsonParam& node_config) { - try { - // 1. 基础校验 - if (!node_config.json_value_.is_object() || - (!node_config.json_value_.contains("id") && - !node_config.json_value_.contains("alias"))) { - BMFLOG(BMF_ERROR) << "[dynamic_remove_node] 缺少 id 或 alias"; - return -1; - } - - // 2. 构造删除配置 - JsonParam update_cfg; - update_cfg.json_value_["nodes"] = - nlohmann::json::array({node_config.json_value_}); - update_cfg.json_value_["nodes"][0]["action"] = "remove"; - update_cfg.json_value_["option"] = nlohmann::json::object(); - - // 3. 调用 update - BMFLOG(BMF_INFO) << "[dynamic_remove_node] 调用 update 配置:\n" - << update_cfg.json_value_.dump(4); - - return Update(update_cfg); - - } catch (const std::exception& e) { - BMFLOG(BMF_ERROR) << "[dynamic_remove_node] 异常: " << e.what(); - return -1; - } -} - - // ----------------- 动态重置节点 ----------------- nlohmann::json Graph::DynamicResetNode(const bmf_sdk::JsonParam &node_config) { try { diff --git a/bmf/test/cpp_builder/cpp_dynamic_test.cpp b/bmf/test/cpp_builder/cpp_dynamic_test.cpp index 61d25109..0fc95d70 100644 --- a/bmf/test/cpp_builder/cpp_dynamic_test.cpp +++ b/bmf/test/cpp_builder/cpp_dynamic_test.cpp @@ -94,125 +94,6 @@ TEST(cpp_dynamic_reset, reset_pass_through_node) { BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 测试通过:动态重置功能正常,输出文件符合预期"; } -// 动态添加功能测试 -TEST(cpp_dynamic_add, add_decoder_and_encoder_only) { - // 1. 路径配置 - const std::string input_file = "../../files/big_bunny_10s_30fps.mp4"; - const std::string input_file2 = "../../files/big_bunny_10s_30fps.mp4"; - const std::string output_file = "./output.mp4"; - BMF_CPP_FILE_REMOVE(output_file); - - // 2. 创建主图 - nlohmann::json graph_para = {{"dump_graph", 1}}; - auto main_graph = bmf::builder::Graph(bmf::builder::NormalMode, - bmf_sdk::JsonParam(graph_para)); - BMFLOG(BMF_INFO) << "[cpp_dynamic_add] 主图创建完成"; - - // 3. 添加解码器节点 - nlohmann::json decode_para = { - {"input_path", input_file}, - {"alias", "decoder"} - }; - auto decoder_node = main_graph.Decode(bmf_sdk::JsonParam(decode_para), - "decoder0"); - auto video_stream = decoder_node["video"]; - auto audio_stream = decoder_node["audio"]; - BMFLOG(BMF_INFO) << "[cpp_dynamic_add] 解码器节点创建完成:alias=decoder0"; - - std::vector pass_through_inputs; - // 4.Graph::Module - bmf_sdk::JsonParam pass_through_option(nlohmann::json::object()); - - auto pass_through_node = main_graph.Module( - pass_through_inputs, - "pass_through", - bmf::builder::ModuleType::CPP, - pass_through_option, - "pass_through", - "", - "", - bmf::builder::InputManagerType::Immediate, - 0 - ); - BMFLOG(BMF_INFO) << "[cpp_dynamic_add] pass_through模块创建完成"; - - // 5. 非阻塞启动图 - main_graph.Start(true, true); - BMFLOG(BMF_INFO) << "[cpp_dynamic_add] 主图非阻塞启动"; - std::this_thread::sleep_for(std::chrono::milliseconds(20)); - - // 构造decoder1的动态配置 - nlohmann::json decoder1_config = { - {"alias", "decoder1"}, - {"module_info", { - {"name", "c_ffmpeg_decoder"}, - {"type", "c++"} - }}, - {"option", { - {"input_path", input_file2}, - {"alias", "decoder1"} - }}, - {"output_streams", nlohmann::json::array({ - {{"identifier", "pass_through.0_0"}, {"alias", "video"}}, - {{"identifier", "pass_through.0_1"}, {"alias", "audio"}} - })}, - {"input_manager", "immediate"}, - {"scheduler", 0} - }; - // 调用dynamic_add_node - bmf_sdk::JsonParam decoder1_param(decoder1_config); - int add_decoder_ret = main_graph.DynamicAddNode(decoder1_param); - if (add_decoder_ret != 0) { - BMFLOG(BMF_ERROR) << "[cpp_dynamic_add] decoder1添加失败,返回码:" << add_decoder_ret; - FAIL() << "decoder1添加失败"; - } - BMFLOG(BMF_INFO) << "[cpp_dynamic_add] decoder1动态添加完成"; - std::this_thread::sleep_for(std::chrono::milliseconds(30)); - - - // 7. 动态添加encoder1 - nlohmann::json encoder1_config = { - {"alias", "encoder1"}, - {"module_info", { - {"name", "c_ffmpeg_encoder"}, - {"type", "c++"} - }}, - {"option", { - {"output_path", output_file}, - {"alias", "encoder1"} - }}, - {"input_streams", nlohmann::json::array({ - {{"identifier", "pass_through.1_0"}, {"alias", "video"}}, - {{"identifier", "pass_through.1_1"}, {"alias", "audio"}} - })}, - {"input_manager", "immediate"}, - {"scheduler", 1} - }; - // 调用dynamic_add_node添加编码器 - bmf_sdk::JsonParam encoder1_param(encoder1_config); - int add_encoder_ret = main_graph.DynamicAddNode(encoder1_param); - if (add_encoder_ret != 0) { - BMFLOG(BMF_ERROR) << "[cpp_dynamic_add] encoder1添加失败,返回码:" << add_encoder_ret; - FAIL() << "encoder1添加失败"; - } - BMFLOG(BMF_INFO) << "[cpp_dynamic_add] encoder1动态添加完成"; - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - - - BMFLOG(BMF_INFO) << "[cpp_dynamic_add] 等待编码完成"; - std::this_thread::sleep_for(std::chrono::seconds(2)); - - // 8. 关闭图 - int close_ret = main_graph.Close(); - if (close_ret != 0) { - BMFLOG(BMF_ERROR) << "[cpp_dynamic_add] 图关闭失败,返回码:" << close_ret; - FAIL() << "图关闭失败"; - } - BMFLOG(BMF_INFO) << "[cpp_dynamic_add] 主图已正常关闭"; - - BMFLOG(BMF_INFO) << "[cpp_dynamic_add] 测试通过:动态添加功能正常"; -} - // 测试入口(默认GTest入口) int main(int argc, char **argv) { From 7d53fd05b742f7d5f42823244e673847dde561de Mon Sep 17 00:00:00 2001 From: i-Orangeade <2930430673@qq.com> Date: Sun, 19 Oct 2025 22:22:54 +0800 Subject: [PATCH 04/11] adjust code position --- bmf/engine/connector/include/builder.hpp | 13 ++-- bmf/engine/connector/src/builder.cpp | 93 ++++++++++-------------- 2 files changed, 46 insertions(+), 60 deletions(-) diff --git a/bmf/engine/connector/include/builder.hpp b/bmf/engine/connector/include/builder.hpp index 9e764cef..da4a305e 100644 --- a/bmf/engine/connector/include/builder.hpp +++ b/bmf/engine/connector/include/builder.hpp @@ -239,6 +239,8 @@ class RealGraph : public std::enable_shared_from_this { bool dumpGraph, bool needMerge); int Run(bool dumpGraph, bool needMerge); + int Update(const bmf_sdk::JsonParam& update_config); + nlohmann::json DynamicResetNode(const bmf_sdk::JsonParam& node_config); int Close(); int ForceClose(); Packet Generate(std::string streamName, bool block = true); @@ -619,11 +621,6 @@ class BMF_ENGINE_API Graph { Graph(Graph &&rhs) = default; - int Update(const bmf_sdk::JsonParam& update_config); - - nlohmann::json DynamicResetNode(const bmf_sdk::JsonParam& node_config); - - private: friend class Stream; @@ -650,7 +647,11 @@ class BMF_ENGINE_API Graph { void Start(bool dumpGraph = true, bool needMerge = true); void Start(std::vector& generateStreams, bool dumpGraph = true, bool needMerge = true); - + + int Update(const bmf_sdk::JsonParam& update_config); + + nlohmann::json DynamicResetNode(const bmf_sdk::JsonParam& node_config); + int Close(); int ForceClose(); diff --git a/bmf/engine/connector/src/builder.cpp b/bmf/engine/connector/src/builder.cpp index d821ab3c..419db7d7 100644 --- a/bmf/engine/connector/src/builder.cpp +++ b/bmf/engine/connector/src/builder.cpp @@ -435,6 +435,37 @@ int RealGraph::Run(bool dumpGraph, bool needMerge) { return graphInstance_->close(); } +int RealGraph::Update(const bmf_sdk::JsonParam& update_config) { + std::string config_str = update_config.json_value_.dump(); + BMFLOG(BMF_INFO) << "[RealGraph::Update] 底层配置(原始 JSON): " << config_str; + + graphInstance_->update(config_str, false); + BMFLOG(BMF_INFO) << "[RealGraph::Update] 成功"; + + return 0; +} + +nlohmann::json RealGraph::DynamicResetNode(const bmf_sdk::JsonParam& node_config) { + if (!node_config.json_value_.is_object() || !node_config.json_value_.contains("alias")) { + BMFLOG(BMF_ERROR) << "[RealGraph::DynamicResetNode] 配置无效,缺少 alias"; + return nlohmann::json(); + } + + nlohmann::json node_json; + node_json["action"] = "reset"; + node_json["alias"] = node_config.json_value_["alias"]; + + nlohmann::json option_json = node_config.json_value_; + option_json.erase("alias"); + node_json["option"] = option_json; + + nlohmann::json update_config; + update_config["nodes"] = nlohmann::json::array({node_json}); + + BMFLOG(BMF_INFO) << "[RealGraph::DynamicResetNode] 生成重置配置:\n" << update_config.dump(2); + return update_config; +} + void RealGraph::Start( const std::vector> &streams, bool dumpGraph, bool needMerge) { @@ -822,6 +853,14 @@ void Graph::Start(std::vector &generateStreams, bool dumpGraph, graph_->Start(generateRealStreams, dumpGraph, needMerge); } +int Graph::Update(const bmf_sdk::JsonParam& update_config) { + return graph_->Update(update_config); +} + +nlohmann::json Graph::DynamicResetNode(const bmf_sdk::JsonParam &node_config) { + return graph_->DynamicResetNode(node_config); +} + int Graph::Close() { return graph_->Close(); } @@ -1096,60 +1135,6 @@ int Graph::FillPacket(std::string streamName, Packet packet, bool block) { return graph_->FillPacket(streamName, packet, block); } - - -// ----------------- update ----------------- -int Graph::Update(const bmf_sdk::JsonParam& update_config) { - try { - // 直接传递配置给engine层 - std::string config_str = update_config.json_value_.dump(); - BMFLOG(BMF_INFO) << "[Update] 底层配置(原始 JSON): " << config_str; - - // 调用底层 update - graph_->graphInstance_->update(config_str, false); - BMFLOG(BMF_INFO) << "[Update] 成功"; - - return 0; - } catch (const std::exception& e) { - BMFLOG(BMF_ERROR) << "[Update] 异常: " << e.what(); - return -1; - } -} - - -// ----------------- 动态重置节点 ----------------- -nlohmann::json Graph::DynamicResetNode(const bmf_sdk::JsonParam &node_config) { - try { - // 1. 校验必要字段:只需要 alias - if (!node_config.json_value_.is_object() || - !node_config.json_value_.contains("alias")) { - BMFLOG(BMF_ERROR) << "[DynamicResetNode] 配置无效,缺少 alias"; - return nlohmann::json(); - } - - // 2. 构造极简的 reset 节点配置 - nlohmann::json node_json; - node_json["action"] = "reset"; - node_json["alias"] = node_config.json_value_["alias"]; - - nlohmann::json option_json = node_config.json_value_; - option_json.erase("alias"); - node_json["option"] = option_json; - - // 构造最终 update 配置 - nlohmann::json update_config; - update_config["nodes"] = nlohmann::json::array({node_json}); - - BMFLOG(BMF_INFO) << "[DynamicResetNode] 生成重置配置:\n" << update_config.dump(2); - return update_config; - - } catch (const std::exception &e) { - BMFLOG(BMF_ERROR) << "[DynamicResetNode] 异常: " << e.what(); - return nlohmann::json(); - } -} - - void SyncPackets::Insert(int streamId, std::vector frames) { packets.insert(std::make_pair(streamId, frames)); } From 20182280ee1080b70f41b675e5699c1fc020903d Mon Sep 17 00:00:00 2001 From: i-Orangeade <2930430673@qq.com> Date: Fri, 24 Oct 2025 16:17:49 +0800 Subject: [PATCH 05/11] add new function:SetAction --- bmf/engine/connector/include/builder.hpp | 16 ++++-- bmf/engine/connector/src/builder.cpp | 66 +++++++++++++++-------- bmf/test/cpp_builder/cpp_dynamic_test.cpp | 17 +++--- 3 files changed, 62 insertions(+), 37 deletions(-) diff --git a/bmf/engine/connector/include/builder.hpp b/bmf/engine/connector/include/builder.hpp index da4a305e..f075e5e5 100644 --- a/bmf/engine/connector/include/builder.hpp +++ b/bmf/engine/connector/include/builder.hpp @@ -133,6 +133,8 @@ class RealNode : public std::enable_shared_from_this { void SetAlias(std::string const &alias); + void SetAction(std::string const &action); + void SetInputManager(InputManagerType inputStreamManager); void SetScheduler(int scheduler); @@ -189,6 +191,7 @@ class RealNode : public std::enable_shared_from_this { std::weak_ptr graph_; int id_; std::string alias_; + std::string action_; bmf_sdk::JsonParam option_; std::vector> inputStreams_; std::vector> outputStreams_; @@ -239,8 +242,8 @@ class RealGraph : public std::enable_shared_from_this { bool dumpGraph, bool needMerge); int Run(bool dumpGraph, bool needMerge); - int Update(const bmf_sdk::JsonParam& update_config); - nlohmann::json DynamicResetNode(const bmf_sdk::JsonParam& node_config); + int Update(std::shared_ptr update_graph); + std::shared_ptr DynamicResetNode(const bmf_sdk::JsonParam& node_config); int Close(); int ForceClose(); Packet Generate(std::string streamName, bool block = true); @@ -628,6 +631,9 @@ class BMF_ENGINE_API Graph { std::shared_ptr graph_; + explicit Graph(std::shared_ptr real_graph) + : graph_(real_graph) {} + public: void SetTotalThreadNum(int num); @@ -648,9 +654,9 @@ class BMF_ENGINE_API Graph { void Start(std::vector& generateStreams, bool dumpGraph = true, bool needMerge = true); - int Update(const bmf_sdk::JsonParam& update_config); - - nlohmann::json DynamicResetNode(const bmf_sdk::JsonParam& node_config); + int Update(const Graph& update_graph); + + Graph DynamicResetNode(const bmf_sdk::JsonParam& node_config); int Close(); int ForceClose(); diff --git a/bmf/engine/connector/src/builder.cpp b/bmf/engine/connector/src/builder.cpp index 419db7d7..b9505f94 100644 --- a/bmf/engine/connector/src/builder.cpp +++ b/bmf/engine/connector/src/builder.cpp @@ -151,7 +151,7 @@ RealNode::RealNode(const std::shared_ptr &graph, int id, std::string const &modulePath, std::string const &moduleEntry, InputManagerType inputStreamManager, int scheduler) - : graph_(graph), id_(id), alias_(std::move(alias)), option_(option), + : graph_(graph), id_(id), alias_(std::move(alias)), action_(), option_(option), moduleInfo_({moduleName, moduleType, modulePath, moduleEntry}), metaInfo_(), inputStreams_(std::move(inputStreams)), inputManager_(inputStreamManager), scheduler_(scheduler) { @@ -190,6 +190,10 @@ void RealNode::SetAlias(std::string const &alias) { graph_.lock()->GiveNodeAlias(shared_from_this(), alias); } +void RealNode::SetAction(std::string const &action) { + action_ = action; +} + void RealNode::GiveStreamNotify(int idx, std::string const ¬ify) { auto graph = graph_.lock(); if (graph->existedNodeAlias_.count(notify)) @@ -266,6 +270,12 @@ nlohmann::json RealNode::Dump() { info["output_streams"].push_back(s->Dump()); info["option"] = option_.json_value_; info["scheduler"] = scheduler_; + + // 添加action字段输出 + if (!action_.empty()) { + info["action"] = action_; + } + switch (inputManager_) { case Default: info["input_manager"] = "default"; @@ -435,35 +445,46 @@ int RealGraph::Run(bool dumpGraph, bool needMerge) { return graphInstance_->close(); } -int RealGraph::Update(const bmf_sdk::JsonParam& update_config) { - std::string config_str = update_config.json_value_.dump(); - BMFLOG(BMF_INFO) << "[RealGraph::Update] 底层配置(原始 JSON): " << config_str; +int RealGraph::Update(std::shared_ptr update_graph) { + if (!update_graph) { + BMFLOG(BMF_ERROR) << "[RealGraph::Update] update graph is null"; + return -1; + } + + // 获取更新图的配置 + auto graph_config = update_graph->Dump(); + + std::string config_str = graph_config.dump(); + BMFLOG(BMF_INFO) << "[RealGraph::Update] 转发配置: " << config_str; graphInstance_->update(config_str, false); - BMFLOG(BMF_INFO) << "[RealGraph::Update] 成功"; - + BMFLOG(BMF_INFO) << "[RealGraph::Update] 转发成功"; return 0; } -nlohmann::json RealGraph::DynamicResetNode(const bmf_sdk::JsonParam& node_config) { +std::shared_ptr RealGraph::DynamicResetNode(const bmf_sdk::JsonParam& node_config) { if (!node_config.json_value_.is_object() || !node_config.json_value_.contains("alias")) { BMFLOG(BMF_ERROR) << "[RealGraph::DynamicResetNode] 配置无效,缺少 alias"; - return nlohmann::json(); + return nullptr; } - nlohmann::json node_json; - node_json["action"] = "reset"; - node_json["alias"] = node_config.json_value_["alias"]; + std::string alias = node_config.json_value_["alias"]; + BMFLOG(BMF_INFO) << "[RealGraph::DynamicResetNode] 开始创建重置图,alias: " << alias; + + // 创建一个新的空图 + auto reset_graph = std::make_shared(mode_, bmf_sdk::JsonParam(nlohmann::json::object())); - nlohmann::json option_json = node_config.json_value_; - option_json.erase("alias"); - node_json["option"] = option_json; + // 在当前图中创建重置节点 + std::vector> empty_inputs; + auto node = reset_graph->AddModule(alias, bmf_sdk::JsonParam(node_config.json_value_), + empty_inputs, "", Python, "", "", Immediate, 0); - nlohmann::json update_config; - update_config["nodes"] = nlohmann::json::array({node_json}); + // 设置节点的action为"reset" + node->SetAction("reset"); + BMFLOG(BMF_INFO) << "[RealGraph::DynamicResetNode] 设置节点action为reset"; - BMFLOG(BMF_INFO) << "[RealGraph::DynamicResetNode] 生成重置配置:\n" << update_config.dump(2); - return update_config; + BMFLOG(BMF_INFO) << "[RealGraph::DynamicReset] 重置图创建成功,alias: " << alias; + return reset_graph; } void RealGraph::Start( @@ -853,12 +874,13 @@ void Graph::Start(std::vector &generateStreams, bool dumpGraph, graph_->Start(generateRealStreams, dumpGraph, needMerge); } -int Graph::Update(const bmf_sdk::JsonParam& update_config) { - return graph_->Update(update_config); +int Graph::Update(const Graph& update_graph) { + return graph_->Update(update_graph.graph_); } -nlohmann::json Graph::DynamicResetNode(const bmf_sdk::JsonParam &node_config) { - return graph_->DynamicResetNode(node_config); +Graph Graph::DynamicResetNode(const bmf_sdk::JsonParam& node_config) { + auto reset_graph = graph_->DynamicResetNode(node_config); + return Graph(reset_graph); } int Graph::Close() { diff --git a/bmf/test/cpp_builder/cpp_dynamic_test.cpp b/bmf/test/cpp_builder/cpp_dynamic_test.cpp index 0fc95d70..64c5051f 100644 --- a/bmf/test/cpp_builder/cpp_dynamic_test.cpp +++ b/bmf/test/cpp_builder/cpp_dynamic_test.cpp @@ -47,8 +47,8 @@ TEST(cpp_dynamic_reset, reset_pass_through_node) { ); BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 待重置节点创建完成"; - // 4. 非阻塞启动图(对应 Python 层 run_wo_block,匹配 Graph::Start API) - main_graph.Start(true, true); // 参数1:dump_graph(true=打印图配置),参数2:needMerge(true=合并配置) + // 4. 非阻塞启动图 + main_graph.Start(true, true); BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 图非阻塞启动,等待20ms确保节点初始化"; std::this_thread::sleep_for(std::chrono::milliseconds(20)); @@ -67,14 +67,11 @@ TEST(cpp_dynamic_reset, reset_pass_through_node) { bmf_sdk::JsonParam reset_config_param(reset_config); BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 动态重置配置:\n" << reset_config.dump(2); - nlohmann::json reset_update_config = main_graph.DynamicResetNode(reset_config_param); - if (reset_update_config.is_null()) { - BMFLOG(BMF_ERROR) << "[cpp_dynamic_reset] 动态重置配置生成失败"; - FAIL() << "动态重置配置生成失败"; - } + // 6. 创建重置图 + auto reset_graph = main_graph.DynamicResetNode(reset_config_param); - // 执行实际的更新操作 - int update_ret = main_graph.Update(bmf_sdk::JsonParam(reset_update_config)); + // 7. 执行实际的更新操作 + int update_ret = main_graph.Update(reset_graph); if (update_ret != 0) { BMFLOG(BMF_ERROR) << "[cpp_dynamic_reset] 动态重置调用失败,返回码:" << update_ret; FAIL() << "动态重置节点调用失败"; @@ -83,7 +80,7 @@ TEST(cpp_dynamic_reset, reset_pass_through_node) { BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 动态重置指令已发送,等待1秒确保处理完成"; std::this_thread::sleep_for(std::chrono::seconds(1)); - // 6. 关闭图(释放资源,匹配 Graph::Close API) + // 8. 关闭图 int close_ret = main_graph.Close(); if (close_ret != 0) { BMFLOG(BMF_ERROR) << "[cpp_dynamic_reset] 图关闭失败,返回码:" << close_ret; From 9b28c8fa7c2a3fa0b4da5f510a30be2bce615f4e Mon Sep 17 00:00:00 2001 From: i-Orangeade <2930430673@qq.com> Date: Fri, 24 Oct 2025 22:03:49 +0800 Subject: [PATCH 06/11] delete constructor --- bmf/engine/connector/include/builder.hpp | 3 --- bmf/engine/connector/src/builder.cpp | 6 ++++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/bmf/engine/connector/include/builder.hpp b/bmf/engine/connector/include/builder.hpp index f075e5e5..f43a72d7 100644 --- a/bmf/engine/connector/include/builder.hpp +++ b/bmf/engine/connector/include/builder.hpp @@ -631,9 +631,6 @@ class BMF_ENGINE_API Graph { std::shared_ptr graph_; - explicit Graph(std::shared_ptr real_graph) - : graph_(real_graph) {} - public: void SetTotalThreadNum(int num); diff --git a/bmf/engine/connector/src/builder.cpp b/bmf/engine/connector/src/builder.cpp index b9505f94..fb7bcb51 100644 --- a/bmf/engine/connector/src/builder.cpp +++ b/bmf/engine/connector/src/builder.cpp @@ -879,8 +879,10 @@ int Graph::Update(const Graph& update_graph) { } Graph Graph::DynamicResetNode(const bmf_sdk::JsonParam& node_config) { - auto reset_graph = graph_->DynamicResetNode(node_config); - return Graph(reset_graph); + auto new_real_graph = graph_->DynamicResetNode(node_config); + Graph reset_graph(new_real_graph->mode_); + reset_graph.graph_ = new_real_graph; + return reset_graph; } int Graph::Close() { From 3e500ee3a84aa3c8ac3d612cb999627358b06f15 Mon Sep 17 00:00:00 2001 From: i-Orangeade <2930430673@qq.com> Date: Sat, 25 Oct 2025 16:54:13 +0800 Subject: [PATCH 07/11] adjust the test code and reset logic --- bmf/engine/connector/include/builder.hpp | 4 ++-- bmf/engine/connector/src/builder.cpp | 27 +++++++-------------- bmf/test/cpp_builder/cpp_dynamic_test.cpp | 29 ++++++++++++----------- 3 files changed, 26 insertions(+), 34 deletions(-) diff --git a/bmf/engine/connector/include/builder.hpp b/bmf/engine/connector/include/builder.hpp index f43a72d7..47f88c91 100644 --- a/bmf/engine/connector/include/builder.hpp +++ b/bmf/engine/connector/include/builder.hpp @@ -243,7 +243,7 @@ class RealGraph : public std::enable_shared_from_this { int Run(bool dumpGraph, bool needMerge); int Update(std::shared_ptr update_graph); - std::shared_ptr DynamicResetNode(const bmf_sdk::JsonParam& node_config); + void DynamicResetNode(const bmf_sdk::JsonParam& node_config); int Close(); int ForceClose(); Packet Generate(std::string streamName, bool block = true); @@ -653,7 +653,7 @@ class BMF_ENGINE_API Graph { int Update(const Graph& update_graph); - Graph DynamicResetNode(const bmf_sdk::JsonParam& node_config); + void DynamicResetNode(const bmf_sdk::JsonParam& node_config); int Close(); int ForceClose(); diff --git a/bmf/engine/connector/src/builder.cpp b/bmf/engine/connector/src/builder.cpp index fb7bcb51..eac8be4d 100644 --- a/bmf/engine/connector/src/builder.cpp +++ b/bmf/engine/connector/src/builder.cpp @@ -151,7 +151,7 @@ RealNode::RealNode(const std::shared_ptr &graph, int id, std::string const &modulePath, std::string const &moduleEntry, InputManagerType inputStreamManager, int scheduler) - : graph_(graph), id_(id), alias_(std::move(alias)), action_(), option_(option), + : graph_(graph), id_(id), alias_(std::move(alias)), option_(option), moduleInfo_({moduleName, moduleType, modulePath, moduleEntry}), metaInfo_(), inputStreams_(std::move(inputStreams)), inputManager_(inputStreamManager), scheduler_(scheduler) { @@ -462,29 +462,23 @@ int RealGraph::Update(std::shared_ptr update_graph) { return 0; } -std::shared_ptr RealGraph::DynamicResetNode(const bmf_sdk::JsonParam& node_config) { +void RealGraph::DynamicResetNode(const bmf_sdk::JsonParam& node_config) { if (!node_config.json_value_.is_object() || !node_config.json_value_.contains("alias")) { BMFLOG(BMF_ERROR) << "[RealGraph::DynamicResetNode] 配置无效,缺少 alias"; - return nullptr; + return; } std::string alias = node_config.json_value_["alias"]; BMFLOG(BMF_INFO) << "[RealGraph::DynamicResetNode] 开始创建重置图,alias: " << alias; - // 创建一个新的空图 - auto reset_graph = std::make_shared(mode_, bmf_sdk::JsonParam(nlohmann::json::object())); - // 在当前图中创建重置节点 std::vector> empty_inputs; - auto node = reset_graph->AddModule(alias, bmf_sdk::JsonParam(node_config.json_value_), - empty_inputs, "", Python, "", "", Immediate, 0); + auto reset_node = AddModule(alias, bmf_sdk::JsonParam(node_config.json_value_), + empty_inputs, "", Python, "", "", Immediate, 0); // 设置节点的action为"reset" - node->SetAction("reset"); - BMFLOG(BMF_INFO) << "[RealGraph::DynamicResetNode] 设置节点action为reset"; - - BMFLOG(BMF_INFO) << "[RealGraph::DynamicReset] 重置图创建成功,alias: " << alias; - return reset_graph; + reset_node->SetAction("reset"); + BMFLOG(BMF_INFO) << "[RealGraph::DynamicResetNode] 重置节点配置完成,已标记action:reset,alias: " << alias; } void RealGraph::Start( @@ -878,11 +872,8 @@ int Graph::Update(const Graph& update_graph) { return graph_->Update(update_graph.graph_); } -Graph Graph::DynamicResetNode(const bmf_sdk::JsonParam& node_config) { - auto new_real_graph = graph_->DynamicResetNode(node_config); - Graph reset_graph(new_real_graph->mode_); - reset_graph.graph_ = new_real_graph; - return reset_graph; +void Graph::DynamicResetNode(const bmf_sdk::JsonParam& node_config) { + graph_->DynamicResetNode(node_config); } int Graph::Close() { diff --git a/bmf/test/cpp_builder/cpp_dynamic_test.cpp b/bmf/test/cpp_builder/cpp_dynamic_test.cpp index 64c5051f..a4a90771 100644 --- a/bmf/test/cpp_builder/cpp_dynamic_test.cpp +++ b/bmf/test/cpp_builder/cpp_dynamic_test.cpp @@ -14,19 +14,17 @@ TEST(cpp_dynamic_reset, reset_pass_through_node) { BMF_CPP_FILE_REMOVE(output_file); // 1. 创建主图 - nlohmann::json graph_para = {{"dump_graph", 1}}; - auto main_graph = bmf::builder::Graph(bmf::builder::NormalMode, - bmf_sdk::JsonParam(graph_para)); + auto main_graph = bmf::builder::Graph(bmf::builder::NormalMode); BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 主图创建完成"; - // 3. 添加解码器节点 + // 2. 添加解码器节点 nlohmann::json decode_para = { - {"input_path", input_file} + {"input_path", input_file}, + {"alias", "decoder0"} }; - auto decoder_node = main_graph.Decode(bmf_sdk::JsonParam(decode_para), - "decoder0"); // 第二个参数是节点别名 - auto video_stream = decoder_node["video"]; // 提取视频流 - auto audio_stream = decoder_node["audio"]; // 提取音频流 + auto decoder_node = main_graph.Decode(bmf_sdk::JsonParam(decode_para)); + auto video_stream = decoder_node["video"]; + auto audio_stream = decoder_node["audio"]; BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 解码器节点创建完成:alias=decoder0"; // 3. 添加待重置 PassThrough 节点 @@ -67,11 +65,14 @@ TEST(cpp_dynamic_reset, reset_pass_through_node) { bmf_sdk::JsonParam reset_config_param(reset_config); BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 动态重置配置:\n" << reset_config.dump(2); - // 6. 创建重置图 - auto reset_graph = main_graph.DynamicResetNode(reset_config_param); + // 6. 创建空重置图 + auto temp_graph = bmf::builder::Graph(bmf::builder::NormalMode); - // 7. 执行实际的更新操作 - int update_ret = main_graph.Update(reset_graph); + // 7. 临时图描述重置信息 + temp_graph.DynamicResetNode(reset_config_param); + + // 8. 主图执行更新 + int update_ret = main_graph.Update(temp_graph); if (update_ret != 0) { BMFLOG(BMF_ERROR) << "[cpp_dynamic_reset] 动态重置调用失败,返回码:" << update_ret; FAIL() << "动态重置节点调用失败"; @@ -80,7 +81,7 @@ TEST(cpp_dynamic_reset, reset_pass_through_node) { BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 动态重置指令已发送,等待1秒确保处理完成"; std::this_thread::sleep_for(std::chrono::seconds(1)); - // 8. 关闭图 + // 9. 关闭图 int close_ret = main_graph.Close(); if (close_ret != 0) { BMFLOG(BMF_ERROR) << "[cpp_dynamic_reset] 图关闭失败,返回码:" << close_ret; From 85e09c7ed2383f2efddb8ff8a369854718e07f96 Mon Sep 17 00:00:00 2001 From: i-Orangeade <2930430673@qq.com> Date: Sat, 25 Oct 2025 18:11:51 +0800 Subject: [PATCH 08/11] remove Set method --- bmf/engine/connector/include/builder.hpp | 8 +++--- bmf/engine/connector/src/builder.cpp | 32 ++++++++--------------- bmf/test/cpp_builder/cpp_dynamic_test.cpp | 2 +- 3 files changed, 15 insertions(+), 27 deletions(-) diff --git a/bmf/engine/connector/include/builder.hpp b/bmf/engine/connector/include/builder.hpp index 47f88c91..a9b33208 100644 --- a/bmf/engine/connector/include/builder.hpp +++ b/bmf/engine/connector/include/builder.hpp @@ -133,8 +133,6 @@ class RealNode : public std::enable_shared_from_this { void SetAlias(std::string const &alias); - void SetAction(std::string const &action); - void SetInputManager(InputManagerType inputStreamManager); void SetScheduler(int scheduler); @@ -243,7 +241,7 @@ class RealGraph : public std::enable_shared_from_this { int Run(bool dumpGraph, bool needMerge); int Update(std::shared_ptr update_graph); - void DynamicResetNode(const bmf_sdk::JsonParam& node_config); + void DynamicReset(const bmf_sdk::JsonParam& node_config); int Close(); int ForceClose(); Packet Generate(std::string streamName, bool block = true); @@ -624,7 +622,7 @@ class BMF_ENGINE_API Graph { Graph(Graph &&rhs) = default; - private: + private: friend class Stream; friend Node; @@ -653,7 +651,7 @@ class BMF_ENGINE_API Graph { int Update(const Graph& update_graph); - void DynamicResetNode(const bmf_sdk::JsonParam& node_config); + void DynamicReset(const bmf_sdk::JsonParam& node_config); int Close(); int ForceClose(); diff --git a/bmf/engine/connector/src/builder.cpp b/bmf/engine/connector/src/builder.cpp index eac8be4d..a369711b 100644 --- a/bmf/engine/connector/src/builder.cpp +++ b/bmf/engine/connector/src/builder.cpp @@ -190,10 +190,6 @@ void RealNode::SetAlias(std::string const &alias) { graph_.lock()->GiveNodeAlias(shared_from_this(), alias); } -void RealNode::SetAction(std::string const &action) { - action_ = action; -} - void RealNode::GiveStreamNotify(int idx, std::string const ¬ify) { auto graph = graph_.lock(); if (graph->existedNodeAlias_.count(notify)) @@ -271,10 +267,8 @@ nlohmann::json RealNode::Dump() { info["option"] = option_.json_value_; info["scheduler"] = scheduler_; - // 添加action字段输出 - if (!action_.empty()) { + if (!action_.empty()) info["action"] = action_; - } switch (inputManager_) { case Default: @@ -451,10 +445,7 @@ int RealGraph::Update(std::shared_ptr update_graph) { return -1; } - // 获取更新图的配置 - auto graph_config = update_graph->Dump(); - - std::string config_str = graph_config.dump(); + std::string config_str = to_string(update_graph->Dump()); BMFLOG(BMF_INFO) << "[RealGraph::Update] 转发配置: " << config_str; graphInstance_->update(config_str, false); @@ -462,23 +453,22 @@ int RealGraph::Update(std::shared_ptr update_graph) { return 0; } -void RealGraph::DynamicResetNode(const bmf_sdk::JsonParam& node_config) { +void RealGraph::DynamicReset(const bmf_sdk::JsonParam& node_config) { if (!node_config.json_value_.is_object() || !node_config.json_value_.contains("alias")) { - BMFLOG(BMF_ERROR) << "[RealGraph::DynamicResetNode] 配置无效,缺少 alias"; + BMFLOG(BMF_ERROR) << "[RealGraph::DynamicReset] 配置无效,缺少 alias"; return; } std::string alias = node_config.json_value_["alias"]; - BMFLOG(BMF_INFO) << "[RealGraph::DynamicResetNode] 开始创建重置图,alias: " << alias; + BMFLOG(BMF_INFO) << "[RealGraph::DynamicReset] 开始创建重置图,alias: " << alias; - // 在当前图中创建重置节点 - std::vector> empty_inputs; + // 创建重置节点 auto reset_node = AddModule(alias, bmf_sdk::JsonParam(node_config.json_value_), - empty_inputs, "", Python, "", "", Immediate, 0); + {}, "", Python, "", "", Immediate, 0); // 设置节点的action为"reset" - reset_node->SetAction("reset"); - BMFLOG(BMF_INFO) << "[RealGraph::DynamicResetNode] 重置节点配置完成,已标记action:reset,alias: " << alias; + reset_node->action_ = "reset"; + BMFLOG(BMF_INFO) << "[RealGraph::DynamicReset] 重置节点配置完成,已标记action:reset,alias: " << alias; } void RealGraph::Start( @@ -872,8 +862,8 @@ int Graph::Update(const Graph& update_graph) { return graph_->Update(update_graph.graph_); } -void Graph::DynamicResetNode(const bmf_sdk::JsonParam& node_config) { - graph_->DynamicResetNode(node_config); +void Graph::DynamicReset(const bmf_sdk::JsonParam& node_config) { + graph_->DynamicReset(node_config); } int Graph::Close() { diff --git a/bmf/test/cpp_builder/cpp_dynamic_test.cpp b/bmf/test/cpp_builder/cpp_dynamic_test.cpp index a4a90771..ed8faccb 100644 --- a/bmf/test/cpp_builder/cpp_dynamic_test.cpp +++ b/bmf/test/cpp_builder/cpp_dynamic_test.cpp @@ -69,7 +69,7 @@ TEST(cpp_dynamic_reset, reset_pass_through_node) { auto temp_graph = bmf::builder::Graph(bmf::builder::NormalMode); // 7. 临时图描述重置信息 - temp_graph.DynamicResetNode(reset_config_param); + temp_graph.DynamicReset(reset_config_param); // 8. 主图执行更新 int update_ret = main_graph.Update(temp_graph); From 0e009607810b5dd72b8973d0ae3dbb934f0fb594 Mon Sep 17 00:00:00 2001 From: i-Orangeade <2930430673@qq.com> Date: Thu, 30 Oct 2025 14:34:32 +0800 Subject: [PATCH 09/11] modifying error message output and test files --- bmf/engine/connector/src/builder.cpp | 15 +---- bmf/test/cpp_builder/cpp_dynamic_test.cpp | 72 +++++++++-------------- 2 files changed, 31 insertions(+), 56 deletions(-) diff --git a/bmf/engine/connector/src/builder.cpp b/bmf/engine/connector/src/builder.cpp index a369711b..d6a6c497 100644 --- a/bmf/engine/connector/src/builder.cpp +++ b/bmf/engine/connector/src/builder.cpp @@ -441,34 +441,23 @@ int RealGraph::Run(bool dumpGraph, bool needMerge) { int RealGraph::Update(std::shared_ptr update_graph) { if (!update_graph) { - BMFLOG(BMF_ERROR) << "[RealGraph::Update] update graph is null"; - return -1; + throw std::logic_error("Update graph is null."); } - std::string config_str = to_string(update_graph->Dump()); - BMFLOG(BMF_INFO) << "[RealGraph::Update] 转发配置: " << config_str; - graphInstance_->update(config_str, false); - BMFLOG(BMF_INFO) << "[RealGraph::Update] 转发成功"; return 0; } void RealGraph::DynamicReset(const bmf_sdk::JsonParam& node_config) { if (!node_config.json_value_.is_object() || !node_config.json_value_.contains("alias")) { - BMFLOG(BMF_ERROR) << "[RealGraph::DynamicReset] 配置无效,缺少 alias"; - return; + throw std::logic_error("Invalid configuration: missing alias."); } std::string alias = node_config.json_value_["alias"]; - BMFLOG(BMF_INFO) << "[RealGraph::DynamicReset] 开始创建重置图,alias: " << alias; - - // 创建重置节点 auto reset_node = AddModule(alias, bmf_sdk::JsonParam(node_config.json_value_), {}, "", Python, "", "", Immediate, 0); - // 设置节点的action为"reset" reset_node->action_ = "reset"; - BMFLOG(BMF_INFO) << "[RealGraph::DynamicReset] 重置节点配置完成,已标记action:reset,alias: " << alias; } void RealGraph::Start( diff --git a/bmf/test/cpp_builder/cpp_dynamic_test.cpp b/bmf/test/cpp_builder/cpp_dynamic_test.cpp index ed8faccb..6c1c2470 100644 --- a/bmf/test/cpp_builder/cpp_dynamic_test.cpp +++ b/bmf/test/cpp_builder/cpp_dynamic_test.cpp @@ -1,23 +1,19 @@ -#include -#include -#include "gtest/gtest.h" -#include -#include -#include "../include/common.h" -#include "../../connector/include/builder.hpp" -#include "cpp_test_helper.h" +#include "builder.hpp" +#include +#include "nlohmann/json.hpp" +#include "cpp_test_helper.h" -// 动态重置功能测试 +// Dynamic reset function test TEST(cpp_dynamic_reset, reset_pass_through_node) { const std::string output_file = "./output_reset_cpp.mp4"; const std::string input_file = "../../files/big_bunny_10s_30fps.mp4"; BMF_CPP_FILE_REMOVE(output_file); - // 1. 创建主图 + // 1. Create main graph auto main_graph = bmf::builder::Graph(bmf::builder::NormalMode); - BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 主图创建完成"; + BMFLOG(BMF_INFO) << "Main graph created."; - // 2. 添加解码器节点 + // 2. Add decoder node nlohmann::json decode_para = { {"input_path", input_file}, {"alias", "decoder0"} @@ -25,9 +21,9 @@ TEST(cpp_dynamic_reset, reset_pass_through_node) { auto decoder_node = main_graph.Decode(bmf_sdk::JsonParam(decode_para)); auto video_stream = decoder_node["video"]; auto audio_stream = decoder_node["audio"]; - BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 解码器节点创建完成:alias=decoder0"; + BMFLOG(BMF_INFO) << "Decoder node created successfully."; - // 3. 添加待重置 PassThrough 节点 + // 3. Add PassThrough node to be reset std::vector pass_through_inputs = {video_stream, audio_stream}; nlohmann::json pass_through_para = {}; bmf_sdk::JsonParam pass_through_option(nlohmann::json::object()); @@ -43,14 +39,14 @@ TEST(cpp_dynamic_reset, reset_pass_through_node) { bmf::builder::InputManagerType::Immediate, 0 ); - BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 待重置节点创建完成"; + BMFLOG(BMF_INFO) << "PassThrough node created successfully."; - // 4. 非阻塞启动图 - main_graph.Start(true, true); - BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 图非阻塞启动,等待20ms确保节点初始化"; - std::this_thread::sleep_for(std::chrono::milliseconds(20)); - - // 5. 构造动态重置配置 + // 4. Non-blocking start graph + main_graph.Start(true, true); + BMFLOG(BMF_INFO) << "Waiting 20ms to ensure node initialization"; + usleep(20000); + + // 5. Construct dynamic reset configuration nlohmann::json reset_config = { {"alias", "reset_pass_through"}, {"output_path", output_file}, @@ -63,38 +59,28 @@ TEST(cpp_dynamic_reset, reset_pass_through_node) { }} }; bmf_sdk::JsonParam reset_config_param(reset_config); - BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 动态重置配置:\n" << reset_config.dump(2); + BMFLOG(BMF_INFO) << "Dynamic reset configuration:\n" << reset_config.dump(2); - // 6. 创建空重置图 + // 6. Create empty reset graph auto temp_graph = bmf::builder::Graph(bmf::builder::NormalMode); - // 7. 临时图描述重置信息 + // 7. Temporary graph describes reset information temp_graph.DynamicReset(reset_config_param); - // 8. 主图执行更新 + // 8. Main graph performs update int update_ret = main_graph.Update(temp_graph); if (update_ret != 0) { - BMFLOG(BMF_ERROR) << "[cpp_dynamic_reset] 动态重置调用失败,返回码:" << update_ret; - FAIL() << "动态重置节点调用失败"; + BMFLOG(BMF_ERROR) << "Dynamic reset call failed, return code: " << update_ret; + FAIL() << "Dynamic reset node call failed."; } - - BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 动态重置指令已发送,等待1秒确保处理完成"; - std::this_thread::sleep_for(std::chrono::seconds(1)); + BMFLOG(BMF_INFO) << "Waiting 1 second to ensure processing is complete."; + sleep(1); - // 9. 关闭图 + // 9. Close graph int close_ret = main_graph.Close(); if (close_ret != 0) { - BMFLOG(BMF_ERROR) << "[cpp_dynamic_reset] 图关闭失败,返回码:" << close_ret; - FAIL() << "图关闭失败"; + BMFLOG(BMF_ERROR) << "Graph close failed, return code: " << close_ret; + FAIL() << "Graph close failed"; } - BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 主图已正常关闭"; - - BMFLOG(BMF_INFO) << "[cpp_dynamic_reset] 测试通过:动态重置功能正常,输出文件符合预期"; + BMFLOG(BMF_INFO) << "Main graph closed successfully."; } - - -// 测试入口(默认GTest入口) -int main(int argc, char **argv) { - testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} \ No newline at end of file From c3151118dbde5991ed4d147e79028b9092367bd1 Mon Sep 17 00:00:00 2001 From: i-Orangeade <2930430673@qq.com> Date: Thu, 30 Oct 2025 20:50:22 +0800 Subject: [PATCH 10/11] modify reset logic:can handle multiple nodes --- bmf/engine/connector/src/builder.cpp | 17 +++++++++++++---- bmf/test/cpp_builder/cpp_dynamic_test.cpp | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/bmf/engine/connector/src/builder.cpp b/bmf/engine/connector/src/builder.cpp index d6a6c497..d34d1547 100644 --- a/bmf/engine/connector/src/builder.cpp +++ b/bmf/engine/connector/src/builder.cpp @@ -452,12 +452,21 @@ void RealGraph::DynamicReset(const bmf_sdk::JsonParam& node_config) { if (!node_config.json_value_.is_object() || !node_config.json_value_.contains("alias")) { throw std::logic_error("Invalid configuration: missing alias."); } + + std::vector reset_alias = node_config.json_value_["alias"].get>(); - std::string alias = node_config.json_value_["alias"]; - auto reset_node = AddModule(alias, bmf_sdk::JsonParam(node_config.json_value_), - {}, "", Python, "", "", Immediate, 0); + if (reset_alias.empty() || std::any_of(reset_alias.begin(), reset_alias.end(), [](const auto& s) { + return s.empty(); + })) { + throw std::logic_error("'alias' array is empty or contains empty strings."); + } + + for (const std::string& alias : reset_alias) { + auto reset_node = AddModule(alias, bmf_sdk::JsonParam(node_config.json_value_), + {}, "", CPP, "", "", Immediate, 0); - reset_node->action_ = "reset"; + reset_node->action_ = "reset"; + } } void RealGraph::Start( diff --git a/bmf/test/cpp_builder/cpp_dynamic_test.cpp b/bmf/test/cpp_builder/cpp_dynamic_test.cpp index 6c1c2470..5cc07df8 100644 --- a/bmf/test/cpp_builder/cpp_dynamic_test.cpp +++ b/bmf/test/cpp_builder/cpp_dynamic_test.cpp @@ -48,7 +48,7 @@ TEST(cpp_dynamic_reset, reset_pass_through_node) { // 5. Construct dynamic reset configuration nlohmann::json reset_config = { - {"alias", "reset_pass_through"}, + {"alias", {"reset_pass_through"}}, {"output_path", output_file}, {"video_params", { {"codec", "h264"}, From b923059069dec08f542795d63266741035ed1f06 Mon Sep 17 00:00:00 2001 From: i-Orangeade <2930430673@qq.com> Date: Thu, 30 Oct 2025 22:49:16 +0800 Subject: [PATCH 11/11] add update and reset interfaces in builder layer ,add dynamic reset test file --- bmf/engine/connector/src/builder.cpp | 17 ++++------------- bmf/test/cpp_builder/cpp_dynamic_test.cpp | 2 +- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/bmf/engine/connector/src/builder.cpp b/bmf/engine/connector/src/builder.cpp index d34d1547..9b2f892a 100644 --- a/bmf/engine/connector/src/builder.cpp +++ b/bmf/engine/connector/src/builder.cpp @@ -452,21 +452,12 @@ void RealGraph::DynamicReset(const bmf_sdk::JsonParam& node_config) { if (!node_config.json_value_.is_object() || !node_config.json_value_.contains("alias")) { throw std::logic_error("Invalid configuration: missing alias."); } - - std::vector reset_alias = node_config.json_value_["alias"].get>(); - if (reset_alias.empty() || std::any_of(reset_alias.begin(), reset_alias.end(), [](const auto& s) { - return s.empty(); - })) { - throw std::logic_error("'alias' array is empty or contains empty strings."); - } - - for (const std::string& alias : reset_alias) { - auto reset_node = AddModule(alias, bmf_sdk::JsonParam(node_config.json_value_), - {}, "", CPP, "", "", Immediate, 0); + std::string alias = node_config.json_value_["alias"]; + auto reset_node = AddModule(alias, bmf_sdk::JsonParam(node_config.json_value_), + {}, "", CPP, "", "", Immediate, 0); - reset_node->action_ = "reset"; - } + reset_node->action_ = "reset"; } void RealGraph::Start( diff --git a/bmf/test/cpp_builder/cpp_dynamic_test.cpp b/bmf/test/cpp_builder/cpp_dynamic_test.cpp index 5cc07df8..6c1c2470 100644 --- a/bmf/test/cpp_builder/cpp_dynamic_test.cpp +++ b/bmf/test/cpp_builder/cpp_dynamic_test.cpp @@ -48,7 +48,7 @@ TEST(cpp_dynamic_reset, reset_pass_through_node) { // 5. Construct dynamic reset configuration nlohmann::json reset_config = { - {"alias", {"reset_pass_through"}}, + {"alias", "reset_pass_through"}, {"output_path", output_file}, {"video_params", { {"codec", "h264"},