Files
VideoPipe/nodes/vp_image_src_node.cpp
2026-06-03 12:43:14 +08:00

132 lines
5.7 KiB
C++

#include "vp_image_src_node.h"
namespace vp_nodes {
vp_image_src_node::vp_image_src_node(std::string node_name,
int channel_index,
std::string port_or_location,
int interval,
float resize_ratio,
bool cycle,
std::string gst_decoder_name):
vp_src_node(node_name, channel_index, resize_ratio),
port_or_location(port_or_location),
interval(interval),
cycle(cycle), gst_decoder_name(gst_decoder_name) {
// make sure not greater than 1 minute (too long) and not lower than 1 second (since it's too quick, use video stream instead directly)
assert(interval >= 1 && interval <= 60);
if (vp_utils::ends_with(port_or_location, "jpeg") || vp_utils::ends_with(port_or_location, "jpg")) {
// read from file
gst_template_file = vp_utils::string_format(gst_template_file, port_or_location.c_str(), cycle ? std::string("true").c_str() : std::string("false").c_str(), gst_decoder_name.c_str(), interval);
from_file = true;
}
else if (port_or_location.find_first_not_of("0123456789") == std::string::npos) {
// receive from remote via udp
auto port = std::stoi(port_or_location); // try to get port
gst_template_udp = vp_utils::string_format(gst_template_udp, port, gst_decoder_name.c_str(), interval);
from_file = false;
}
else {
throw "invalid input parameter for `port_or_location`!";
}
auto s = from_file ? gst_template_file : gst_template_udp;
VP_INFO(vp_utils::string_format("[%s] [%s]", node_name.c_str(), s.c_str()));
this->initialized();
}
vp_image_src_node::~vp_image_src_node() {
deinitialized();
}
void vp_image_src_node::handle_run() {
cv::Mat frame;
int video_width = 0;
int video_height = 0;
int fps = 0;
std::chrono::milliseconds delta;
while(alive) {
// check if need work
gate.knock();
auto last_time = std::chrono::system_clock::now();
// try to open capture
if (!image_capture.isOpened()) {
auto gst_launch_str = from_file ? gst_template_file : gst_template_udp;
if(!image_capture.open(gst_launch_str, cv::CAP_GSTREAMER)) {
VP_WARN(vp_utils::string_format("[%s] open image capture failed, try again...", node_name.c_str()));
continue;
}
}
// video properties
if (video_width == 0 || video_height == 0 || fps == 0) {
video_width = image_capture.get(cv::CAP_PROP_FRAME_WIDTH);
video_height = image_capture.get(cv::CAP_PROP_FRAME_HEIGHT);
fps = image_capture.get(cv::CAP_PROP_FPS);
fps = fps < 1 ? 1 : fps; // since fps is too small (0.1 means 1 frame every 10 seconds)
delta = std::chrono::milliseconds(1000 / fps);
original_fps = fps;
original_width = video_width;
original_height = video_height;
}
// stream_info_hooker activated if need
vp_stream_info stream_info {channel_index, original_fps, original_width, original_height, to_string()};
invoke_stream_info_hooker(node_name, stream_info);
image_capture >> frame;
if(frame.empty()) {
VP_WARN(vp_utils::string_format("[%s] reading frame empty, total frame==>%d", node_name.c_str(), frame_index));
continue;
}
// need resize
cv::Mat resize_frame;
if (this->resize_ratio != 1.0f) {
cv::resize(frame, resize_frame, cv::Size(), resize_ratio, resize_ratio);
}
else {
resize_frame = frame.clone(); // clone!
}
// set true size because resize
video_width = resize_frame.cols;
video_height = resize_frame.rows;
this->frame_index++;
// create frame meta
auto out_meta =
std::make_shared<vp_objects::vp_frame_meta>(resize_frame, this->frame_index, this->channel_index, video_width, video_height, fps);
if (out_meta != nullptr) {
this->out_queue.push(out_meta);
// handled hooker activated if need
if (this->meta_handled_hooker) {
meta_handled_hooker(node_name, out_queue.size(), out_meta);
}
// important! notify consumer of out_queue in case it is waiting.
this->out_queue_semaphore.signal();
VP_DEBUG(vp_utils::string_format("[%s] after handling meta, out_queue.size()==>%d", node_name.c_str(), out_queue.size()));
}
// for fps
auto snap = std::chrono::system_clock::now() - last_time;
snap = std::chrono::duration_cast<std::chrono::milliseconds>(snap);
if (snap < delta) {
std::this_thread::sleep_for(delta - snap);
}
}
// send dead flag for dispatch_thread
this->out_queue.push(nullptr);
this->out_queue_semaphore.signal();
}
std::string vp_image_src_node::to_string() {
return from_file ? port_or_location : "udp://127.0.0.1:" + port_or_location + "/jpg";
}
}