Files
VideoPipe/utils/vp_pipe_checker.h
2026-06-03 12:43:14 +08:00

180 lines
7.7 KiB
C++
Executable File

#pragma once
#include <sstream>
#include "vp_version.h"
#include "../nodes/vp_node.h"
#include "../excepts/vp_invalid_pipeline_error.h"
namespace vp_utils {
class vp_pipe_checker
{
private:
// we can only handle the pipeline structure like below, totally symmetrical vertically for each layer.
/*
* |1st layer| |2nd layer| |3rd layer| |4th layer| |5th layer|
* node -...- node \ / node -...- node
*
* node -...- node - -...- node -...- node -...- node
*
* node -...- node / \ node -...- node
*
*/
void check_layer(std::vector<std::shared_ptr<vp_nodes::vp_node>> nodes_in_layer) {
num_layers_in_pipe++;
int next_nodes_num = -1;
std::vector<std::shared_ptr<vp_nodes::vp_node>> all_next_nodes;
// check for:
// 1. node type of start/end point of pipe
// 2. node names in pipe
// 3. next nodes number
for(auto& i : nodes_in_layer) {
// check for the first layer, all nodes MUST be vp_nodes::vp_node_type::SRC
if (num_layers_in_pipe == 1 &&
i->node_type() != vp_nodes::vp_node_type::SRC) {
throw vp_excepts::vp_invalid_pipeline_error("pipe MUST starts with SRC nodes!");
}
auto name = i->node_name;
// check if node name duplicated
if (std::find_if(std::begin(node_names_in_pipe),
std::end(node_names_in_pipe),
[&](std::pair<int, std::vector<std::string>> p){ return std::find(std::begin(p.second), std::end(p.second), name) != std::end(p.second);})
!=
std::end(node_names_in_pipe)) {
throw vp_excepts::vp_invalid_pipeline_error("node names MUST not be duplicated in pipe!");
}
node_names_in_pipe[num_layers_in_pipe].push_back(name);
auto next_nodes = i->next_nodes();
auto _num = next_nodes.size();
// check for the last layer, all nodes MUST be vp_nodes::vp_node_type::DES
if (_num == 0 && i->node_type() != vp_nodes::vp_node_type::DES) {
throw vp_excepts::vp_invalid_pipeline_error("pipe MUST ends with DES nodes!");
}
// initialize next_nodes_num variable, all nodes in current layer should have the same next_nodes_num.
if (next_nodes_num == -1) {
next_nodes_num = _num;
}
// the next nodes number of each node in the same layer must be equal (all are 0 for des nodes).
if (next_nodes_num != _num) {
throw vp_excepts::vp_invalid_pipeline_error("all nodes in the same layer MUST have the same next nodes number!");
}
// merge next nodes of each node into a big vector
all_next_nodes.insert(all_next_nodes.end(), next_nodes.begin(), next_nodes.end());
}
// check for 2 conditions:
// 1. all next nodes are the same, or
// 2. all next nodes are distinc.
if (all_next_nodes.size() != 0) {
bool all_the_same = true;
bool all_distinct = true;
// check if all the next nodes are the same
for(auto & i: all_next_nodes) {
if (i != all_next_nodes[0])
{
all_the_same = false;
break;
}
}
// check if all next nodes are distinct
if (!all_the_same) {
std::sort(std::begin(all_next_nodes), std::end(all_next_nodes));
auto pos = std::adjacent_find(std::begin(all_next_nodes), std::end(all_next_nodes));
if (pos != std::end(all_next_nodes)) {
all_distinct = false;
}
}
if (!all_the_same && !all_distinct) {
throw vp_excepts::vp_invalid_pipeline_error("the next nodes of each node in the same layer MUST be the same or be distinct totally!");
}
// just keep the first one if all the next nodes are the same
if (all_the_same) {
all_next_nodes.erase(all_next_nodes.begin() + 1, all_next_nodes.end());
}
// recursion for next layer
check_layer(all_next_nodes);
}
}
// layer_index -> node_names
std::map<int, std::vector<std::string>> node_names_in_pipe;
int num_layers_in_pipe = 0;
bool summary;
public:
vp_pipe_checker(bool summary = true) {
summary = summary;
}
// total layers
int pipe_width() {
return num_layers_in_pipe;
}
// max number of nodes in all layers
int pipe_height() {
int number = 0;
for(auto & i : node_names_in_pipe) {
if (i.second.size() > number) {
number = i.second.size();
}
}
return number;
}
void operator()(std::vector<std::shared_ptr<vp_nodes::vp_node>> pipe_src_nodes) {
// start check with the 1st layer
check_layer(pipe_src_nodes);
if (summary) {
/*
std::cout << "############# pipe check summary ##############" << std::endl;
std::cout << " total layers: " << num_layers_in_pipe << std::endl;
std::cout << " layer index, node names" << std::endl;
for(auto & i : node_names_in_pipe) {
std::cout << " " << i.first << " ";
for(auto & j : i.second) {
std::cout << j << ",";
}
std::cout << std::endl;
}
std::cout << ############# pipe check summary ############## << std::endl;
*/
std::ostringstream v_stream;
v_stream << "\n################ version info #################\n";
v_stream << " build_time: " << APP_BUILD_TIME << "\n";
v_stream << " commit_hash: " << APP_GIT_COMMIT << "\n";
v_stream << " version: " << APP_VERSION << "\n";
v_stream << "################ version info ################" << "\n";
// to log
VP_INFO(v_stream.str());
std::ostringstream s_stream;
s_stream << "\n############# pipe check summary ##############\n";
s_stream << " total layers: " << num_layers_in_pipe << "\n";
s_stream << " layer index, node names" << "\n";
for(auto & i : node_names_in_pipe) {
s_stream << " " << i.first << " ";
for(auto & j : i.second) {
s_stream << j << ",";
}
s_stream << "\n";
}
s_stream << "############# pipe check summary ##############" << "\n";
// to log
VP_INFO(s_stream.str());
}
}
};
}