#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_record_node::handle_frame_meta(std::shared_ptr 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>(); } 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>(); } 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_record_node::handle_control_meta(std::shared_ptr 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& 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(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(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(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(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); } } }