wangrong
2025-01-03 2c4b8838f89bebca97615c5f0bac2c58e0349771
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#pragma once
 
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <string>
#include <memory>
#include <chrono>
 
#include "../utils/vp_semaphore.h"
#include "../utils/vp_utils.h"
#include "../utils/logger/vp_logger.h"
#include "vp_meta_publisher.h"
#include "vp_meta_hookable.h"
#include "../objects/vp_control_meta.h"
#include "../objects/vp_frame_meta.h"
#include "../excepts/vp_invalid_calling_error.h"
 
namespace vp_nodes {
    // node type
    enum vp_node_type {
        SRC,  // src node, must not have input branchs
        DES,  // des node, must not have output branchs
        MID   // middle node, can have input and output branchs
    };
 
    // base class for all nodes
    class vp_node: public vp_meta_publisher, 
                    public vp_meta_subscriber, 
                    public vp_meta_hookable, 
                    public std::enable_shared_from_this<vp_node> {
    private:
        // previous nodes
        std::vector<std::shared_ptr<vp_node>> pre_nodes;
 
        // handle thread
        std::thread handle_thread;
        // dispatch thread
        std::thread dispatch_thread;
 
    protected:
        // alive or not for node
        bool alive = true;
 
        // by default we handle frame meta one by one, in some situations we need handle them batch by batch(such as vp_infer_node).
        // setting this member greater than 1 means the node will handle frame meta with batch, and vp_node::handle_frame_meta_by_batch(...) will be called other than vp_node::handle_frame_meta(...).
        // note: control meta is not allowed like above, only one by one supported.
        int frame_meta_handle_batch = 1;
 
        // cache input meta from previous nodes
        std::queue<std::shared_ptr<vp_objects::vp_meta>> in_queue;
        // 
        std::mutex in_queue_lock;
        // cache output meta to next nodes
        std::queue<std::shared_ptr<vp_objects::vp_meta>> out_queue;
 
        // synchronize for in_queue
        vp_utils::vp_semaphore in_queue_semaphore;
        // synchronize for out_queue
        vp_utils::vp_semaphore out_queue_semaphore;
 
        // get meta from in_queue, handle meta and put them into out_queue looply.
        // we need re-implement(define how to create meta and put it into out_queue) in src nodes since they have no previous nodes. 
        virtual void handle_run();
        // get meta from out_queue and push them to next nodes looply.
        // we need re-implement(just do nothing) in des nodes since they have no next nodes. 
        virtual void dispatch_run();
 
        // define how to handle frame meta [one by one], ignored in src nodes.
        // return nullptr means do not push it to next nodes, such as des nodes which have no next nodes.
        virtual std::shared_ptr<vp_objects::vp_meta> handle_frame_meta(std::shared_ptr<vp_objects::vp_frame_meta> meta);
        // define how to handle control meta, ignored in src nodes. 
        // return nullptr means do not push it to next nodes, such as des nodes which have no next nodes.
        virtual std::shared_ptr<vp_objects::vp_meta> handle_control_meta(std::shared_ptr<vp_objects::vp_control_meta> meta);
 
        // define how to handle frame meta [batch by batch], ignored in src nodes.
        virtual void handle_frame_meta(const std::vector<std::shared_ptr<vp_objects::vp_frame_meta>>& meta_with_batch);
 
        // called by child classes after all resources have been initialized (in the last constructor of chain).
        void initialized();
        // called by child classes before all resources going to be destroyed (in the last destructor of chain)。
        virtual void deinitialized();
 
        // push meta to the back of out_queue, then it will be pushed to next nodes in order.
        // take care it's different from vp_node::push_meta(meta) which will push meta to next nodes directly.
        // the method can be called ONLY in handle thread inside node.
        void pendding_meta(std::shared_ptr<vp_objects::vp_meta> meta);
 
        // protected as it can't be instanstiated directly.
        vp_node(std::string node_name);
    public:
        virtual ~vp_node();
        // clear meaningful string, such as 'file_src_0' stands for file source node at channel 0.
        std::string node_name;
 
        // receive meta from previous nodes, 
        // we can hook(such as modifying meta) in child class but do not forget calling vp_node.meta_flow(...) followly.
        virtual void meta_flow(std::shared_ptr<vp_objects::vp_meta> meta) override;
 
        // retrive current node type
        virtual vp_node_type node_type();
        
        // detach myself from all previous nodes
        void detach();
        // detach myself from specific previous nodes
        void detach_from(std::vector<std::string> pre_node_names);
        // detach myself from all previous nodes AND the same action on all next nodes(recursively), can be used to split the whole pipeline into single nodes before process exits.
        void detach_recursively();
        // attach myself to previous nodes(can be a list)
        void attach_to(std::vector<std::shared_ptr<vp_node>> pre_nodes);
 
        // get next nodes
        std::vector<std::shared_ptr<vp_node>> next_nodes();
 
        // get description of node
        virtual std::string to_string();
    };
 
}