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

149 lines
8.0 KiB
C++

#include "vp_record_node.h"
namespace vp_nodes {
vp_record_node::vp_record_node(std::string node_name,
std::string video_save_dir,
std::string image_save_dir,
vp_objects::vp_size resolution_w_h,
bool osd,
int pre_record_video_duration,
int record_video_duration,
bool auto_sub_dir,
int bitrate):
vp_node(node_name),
video_save_dir(video_save_dir),
image_save_dir(image_save_dir),
resolution_w_h(resolution_w_h),
osd(osd),
pre_record_video_duration(pre_record_video_duration),
record_video_duration(record_video_duration),
auto_sub_dir(auto_sub_dir),
bitrate(bitrate) {
this->initialized();
}
vp_record_node::~vp_record_node() {
deinitialized();
}
std::shared_ptr<vp_objects::vp_meta> vp_record_node::handle_frame_meta(std::shared_ptr<vp_objects::vp_frame_meta> meta) {
// cache fps for current channel
if (all_fps.count(meta->channel_index) == 0) {
all_fps[meta->channel_index] = meta->fps;
}
auto& fps = all_fps[meta->channel_index];
// first time for current channel
if (all_pre_records.count(meta->channel_index) == 0) {
all_pre_records[meta->channel_index] = std::deque<std::shared_ptr<vp_objects::vp_frame_meta>>();
}
auto& pre_records = all_pre_records[meta->channel_index];
// update pre_records for current channel
pre_records.push_back(meta);
auto frames_need_pre_record = fps * pre_record_video_duration;
// keep max frames
if (pre_records.size() > frames_need_pre_record) {
pre_records.pop_front();
}
// first time for current channel
if (all_record_tasks.count(meta->channel_index) == 0) {
all_record_tasks[meta->channel_index] = std::list<std::shared_ptr<vp_nodes::vp_record_task>>();
}
auto& record_tasks = all_record_tasks[meta->channel_index];
// then append data to all tasks of current channel
for (auto i = record_tasks.begin(); i != record_tasks.end();) {
if ((*i)->status == vp_nodes::vp_record_task_status::COMPLETE) {
i = record_tasks.erase(i); // remove task which is complete already
}
else {
(*i)->append_async(meta); // no block here
i++;
}
}
// done
return meta;
}
std::shared_ptr<vp_objects::vp_meta> vp_record_node::handle_control_meta(std::shared_ptr<vp_objects::vp_control_meta> meta) {
if (meta->control_type == vp_objects::vp_control_type::IMAGE_RECORD ||
meta->control_type == vp_objects::vp_control_type::VIDEO_RECORD) {
/* code */
// create record task, it will start asynchronously.
auto_new_record_task(meta);
/* no return since already handle it, do not need pass to next nodes. */
return nullptr;
}
else {
return vp_node::handle_control_meta(meta);
}
}
void vp_record_node::auto_new_record_task(std::shared_ptr<vp_objects::vp_control_meta>& meta) {
auto& record_tasks = all_record_tasks[meta->channel_index];
auto& pre_records = all_pre_records[meta->channel_index];
auto& fps = all_fps[meta->channel_index];
// image record
if (meta->control_type == vp_objects::vp_control_type::IMAGE_RECORD) {
auto image_record_control_meta = std::dynamic_pointer_cast<vp_objects::vp_image_record_control_meta>(meta);
// create image record task
auto file_name_without_ext = image_record_control_meta->image_file_name_without_ext;
auto _osd = image_record_control_meta->osd;
VP_INFO(vp_utils::string_format("[%s] [record] create new image record task, file_name_without_ext is: `%s`", node_name.c_str(), file_name_without_ext.c_str()));
auto image_record_task = std::make_shared<vp_nodes::vp_image_record_task>(meta->channel_index,
file_name_without_ext,
image_save_dir,
auto_sub_dir,
_osd,
resolution_w_h, node_name);
image_record_task->set_task_complete_hooker([this](int channel_index, vp_record_info record_info) {
// just notify hooker which has attached on the node
if (this->image_record_complete_hooker) {
this->image_record_complete_hooker(channel_index, record_info);
}
VP_INFO(vp_utils::string_format("[%s] [record] image record task completed, file_name_without_ext is: `%s`", node_name.c_str(), record_info.file_name_without_ext.c_str()));
});
record_tasks.push_back(image_record_task);
}
// video record
if (meta->control_type == vp_objects::vp_control_type::VIDEO_RECORD) {
auto video_record_control_meta = std::dynamic_pointer_cast<vp_objects::vp_video_record_control_meta>(meta);
// create video record task
auto file_name_without_ext = video_record_control_meta->video_file_name_without_ext;
auto _osd = video_record_control_meta->osd;
auto _record_video_duration = video_record_control_meta->record_video_duration;
if (_record_video_duration == 0) {
// use default value
_record_video_duration = record_video_duration;
}
VP_INFO(vp_utils::string_format("[%s] [record] create new video record task, file_name_without_ext is: `%s`", node_name.c_str(), file_name_without_ext.c_str()));
auto video_record_task = std::make_shared<vp_nodes::vp_video_record_task>(meta->channel_index,
pre_records,
file_name_without_ext,
video_save_dir,
auto_sub_dir,
_osd,
resolution_w_h,
bitrate, fps, pre_record_video_duration, _record_video_duration, node_name);
video_record_task->set_task_complete_hooker([this](int channel_index, vp_record_info record_info) {
// just notify hooker which has attached on the node
if (this->video_record_complete_hooker) {
this->video_record_complete_hooker(channel_index, record_info);
}
VP_INFO(vp_utils::string_format("[%s] [record] video record task completed, file_name_without_ext is: `%s`", node_name.c_str(), record_info.file_name_without_ext.c_str()));
});
record_tasks.push_back(video_record_task);
}
}
}