forked from dsutanto/bytetrack-counter-cpp
Fix recording
This commit is contained in:
1 parent
e92857c6a1
commit
5eb122f422
8 files changed
+1787
-41
No files matched your search
+1709
-6
File diff suppressed because it is too large.
Load diff
Binary file not shown.
@@ -138,6 +138,8 @@ RECORD_VIDEO=false
|
|||||||
OUTPUT_FPS=15
|
OUTPUT_FPS=15
|
||||||
# Delay in seconds after batch starts before recording begins (every batch)
|
# Delay in seconds after batch starts before recording begins (every batch)
|
||||||
RECORD_DELAY_SECONDS=10
|
RECORD_DELAY_SECONDS=10
|
||||||
|
# Extra seconds to keep recording after batch end signal before stopping
|
||||||
|
RECORD_END_DELAY=1
|
||||||
# Shared memory directory for recording (fast write, moved to OUTPUT_DIR on close)
|
# Shared memory directory for recording (fast write, moved to OUTPUT_DIR on close)
|
||||||
RECORD_SHM_DIR=/dev/shm/bytetrack-counter
|
RECORD_SHM_DIR=/dev/shm/bytetrack-counter
|
||||||
|
|
||||||
|
|||||||
@@ -142,6 +142,8 @@ void AppConfig::load_from_env(const char* env_path) {
|
|||||||
if (!ofps_s.empty()) output_fps = std::stoi(ofps_s);
|
if (!ofps_s.empty()) output_fps = std::stoi(ofps_s);
|
||||||
auto rds_s = get_env("RECORD_DELAY_SECONDS");
|
auto rds_s = get_env("RECORD_DELAY_SECONDS");
|
||||||
if (!rds_s.empty()) record_delay_seconds = std::stof(rds_s);
|
if (!rds_s.empty()) record_delay_seconds = std::stof(rds_s);
|
||||||
|
auto reds_s = get_env("RECORD_END_DELAY");
|
||||||
|
if (!reds_s.empty()) record_end_delay_seconds = std::stof(reds_s);
|
||||||
record_shm_dir = get_env("RECORD_SHM_DIR", record_shm_dir);
|
record_shm_dir = get_env("RECORD_SHM_DIR", record_shm_dir);
|
||||||
|
|
||||||
auto lse_s = get_env("LIVE_STREAM_ENABLED");
|
auto lse_s = get_env("LIVE_STREAM_ENABLED");
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ struct AppConfig {
|
|||||||
int video_segment_sec = 3600;
|
int video_segment_sec = 3600;
|
||||||
int output_fps = 15;
|
int output_fps = 15;
|
||||||
float record_delay_seconds = 10.0f;
|
float record_delay_seconds = 10.0f;
|
||||||
|
float record_end_delay_seconds = 1.0f;
|
||||||
std::string record_shm_dir = "/dev/shm/bytetrack-counter";
|
std::string record_shm_dir = "/dev/shm/bytetrack-counter";
|
||||||
|
|
||||||
bool live_stream_enabled = false;
|
bool live_stream_enabled = false;
|
||||||
|
|||||||
+7
-5
@@ -225,7 +225,8 @@ int main(int argc, char* argv[]) {
|
|||||||
video_writer = std::make_unique<VideoBatchWriter>(
|
video_writer = std::make_unique<VideoBatchWriter>(
|
||||||
g_config.record_shm_dir, g_config.output_dir,
|
g_config.record_shm_dir, g_config.output_dir,
|
||||||
w, h, static_cast<int>(fps_prop),
|
w, h, static_cast<int>(fps_prop),
|
||||||
g_config.record_delay_seconds);
|
g_config.record_delay_seconds,
|
||||||
|
g_config.record_end_delay_seconds);
|
||||||
auto* vw = video_writer.get();
|
auto* vw = video_writer.get();
|
||||||
store.set_batch_closed_callback([vw](int bn) { vw->on_batch_closed(bn); });
|
store.set_batch_closed_callback([vw](int bn) { vw->on_batch_closed(bn); });
|
||||||
}
|
}
|
||||||
@@ -286,6 +287,9 @@ int main(int argc, char* argv[]) {
|
|||||||
skip_inference = (mean_diff < g_config.motion_threshold);
|
skip_inference = (mean_diff < g_config.motion_threshold);
|
||||||
}
|
}
|
||||||
prev_gray = gray;
|
prev_gray = gray;
|
||||||
|
if (!skip_inference && video_writer) video_writer->note_motion();
|
||||||
|
} else {
|
||||||
|
if (video_writer) video_writer->note_motion();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Detection> detections;
|
std::vector<Detection> detections;
|
||||||
@@ -339,6 +343,7 @@ int main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
// Apply NMS per-class to suppress duplicate boxes
|
// Apply NMS per-class to suppress duplicate boxes
|
||||||
if (na > 0) {
|
if (na > 0) {
|
||||||
|
if (video_writer) video_writer->note_ayam_detection();
|
||||||
auto keep = nms(ayam_mat, ayam_scores_vec);
|
auto keep = nms(ayam_mat, ayam_scores_vec);
|
||||||
int nk = static_cast<int>(keep.size());
|
int nk = static_cast<int>(keep.size());
|
||||||
Eigen::MatrixXf fm(nk, 4);
|
Eigen::MatrixXf fm(nk, 4);
|
||||||
@@ -440,10 +445,7 @@ int main(int argc, char* argv[]) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
ayam_crossed_frame = true;
|
ayam_crossed_frame = true;
|
||||||
if (started_new) {
|
if (started_new) batch_started_frame = true;
|
||||||
batch_started_frame = true;
|
|
||||||
if (video_writer) video_writer->on_new_batch(store.current_batch_number());
|
|
||||||
}
|
|
||||||
crossing_times.push_back(mono);
|
crossing_times.push_back(mono);
|
||||||
ayam_cross_flash[tid] = g_config.cross_flash_frames;
|
ayam_cross_flash[tid] = g_config.cross_flash_frames;
|
||||||
popups.push_back({
|
popups.push_back({
|
||||||
|
|||||||
+55
-24
@@ -11,9 +11,11 @@
|
|||||||
VideoBatchWriter::VideoBatchWriter(const std::string& shm_dir,
|
VideoBatchWriter::VideoBatchWriter(const std::string& shm_dir,
|
||||||
const std::string& output_dir,
|
const std::string& output_dir,
|
||||||
int w, int h, int fps,
|
int w, int h, int fps,
|
||||||
float delay_sec)
|
float delay_sec,
|
||||||
|
float end_delay_sec)
|
||||||
: shm_dir_(shm_dir), output_dir_(output_dir),
|
: shm_dir_(shm_dir), output_dir_(output_dir),
|
||||||
w_(w), h_(h), fps_(fps), delay_sec_(delay_sec)
|
w_(w), h_(h), fps_(fps),
|
||||||
|
delay_sec_(delay_sec), end_delay_sec_(end_delay_sec)
|
||||||
{
|
{
|
||||||
ensure_dir(shm_dir_);
|
ensure_dir(shm_dir_);
|
||||||
ensure_dir(output_dir_);
|
ensure_dir(output_dir_);
|
||||||
@@ -33,51 +35,69 @@ void VideoBatchWriter::ensure_dir(const std::string& dir) {
|
|||||||
std::filesystem::create_directories(dir);
|
std::filesystem::create_directories(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoBatchWriter::on_new_batch(int batch_number) {
|
void VideoBatchWriter::note_motion() {
|
||||||
current_batch_ = batch_number;
|
if (state_ == IDLE) {
|
||||||
delaying_ = true;
|
start_recording();
|
||||||
delay_start_ = std::chrono::steady_clock::now();
|
state_ = SPECULATING;
|
||||||
|
state_start_ = std::chrono::steady_clock::now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoBatchWriter::note_ayam_detection() {
|
||||||
|
if (state_ == SPECULATING) {
|
||||||
|
state_ = CONFIRMED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoBatchWriter::on_batch_closed(int batch_number) {
|
void VideoBatchWriter::on_batch_closed(int batch_number) {
|
||||||
if (recording_ && current_batch_ == batch_number) {
|
current_batch_ = batch_number;
|
||||||
stop_and_move(batch_number);
|
if (state_ == CONFIRMED) {
|
||||||
|
state_ = STOPPING;
|
||||||
|
state_start_ = std::chrono::steady_clock::now();
|
||||||
}
|
}
|
||||||
delaying_ = false;
|
|
||||||
recording_ = false;
|
|
||||||
current_batch_ = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoBatchWriter::feed_frame(const cv::Mat& raw) {
|
void VideoBatchWriter::feed_frame(const cv::Mat& raw) {
|
||||||
if (delaying_) {
|
auto now = std::chrono::steady_clock::now();
|
||||||
auto elapsed = std::chrono::duration<float>(
|
|
||||||
std::chrono::steady_clock::now() - delay_start_).count();
|
if (state_ == SPECULATING) {
|
||||||
|
float elapsed = std::chrono::duration<float>(now - state_start_).count();
|
||||||
if (elapsed >= delay_sec_) {
|
if (elapsed >= delay_sec_) {
|
||||||
delaying_ = false;
|
stop_and_delete();
|
||||||
start_recording(current_batch_);
|
state_ = IDLE;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (recording_ && writer_.isOpened()) {
|
|
||||||
|
if (state_ == STOPPING) {
|
||||||
|
float elapsed = std::chrono::duration<float>(now - state_start_).count();
|
||||||
|
if (elapsed >= end_delay_sec_) {
|
||||||
|
stop_and_move(current_batch_);
|
||||||
|
state_ = IDLE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state_ != IDLE && writer_.isOpened()) {
|
||||||
writer_.write(raw);
|
writer_.write(raw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoBatchWriter::start_recording(int batch_number) {
|
void VideoBatchWriter::start_recording() {
|
||||||
if (writer_.isOpened()) writer_.release();
|
if (writer_.isOpened()) writer_.release();
|
||||||
|
|
||||||
auto t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
|
auto t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
|
||||||
std::ostringstream name;
|
std::ostringstream name;
|
||||||
name << "batch_" << batch_number << "_"
|
name << "batch_pending_"
|
||||||
<< std::put_time(std::localtime(&t), "%Y%m%d_%H%M%S") << ".mp4";
|
<< std::put_time(std::localtime(&t), "%Y%m%d_%H%M%S") << ".mp4";
|
||||||
current_path_ = shm_dir_ + "/" + name.str();
|
current_path_ = shm_dir_ + "/" + name.str();
|
||||||
|
|
||||||
writer_.open(current_path_,
|
writer_.open(current_path_,
|
||||||
cv::VideoWriter::fourcc('a','v','c','1'),
|
cv::VideoWriter::fourcc('a','v','c','1'),
|
||||||
fps_, cv::Size(w_, h_));
|
fps_, cv::Size(w_, h_));
|
||||||
recording_ = writer_.isOpened();
|
|
||||||
|
|
||||||
if (recording_) {
|
if (writer_.isOpened()) {
|
||||||
std::cout << "[RECORD] Started: " << current_path_ << std::endl;
|
std::cout << "[RECORD] Speculating: " << current_path_ << std::endl;
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "[RECORD] Failed to open: " << current_path_ << std::endl;
|
std::cerr << "[RECORD] Failed to open: " << current_path_ << std::endl;
|
||||||
}
|
}
|
||||||
@@ -97,6 +117,18 @@ static void copy_and_clean(const std::string& src, const std::string& dst) {
|
|||||||
std::filesystem::remove(src, ec);
|
std::filesystem::remove(src, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VideoBatchWriter::stop_and_delete() {
|
||||||
|
if (writer_.isOpened()) {
|
||||||
|
writer_.release();
|
||||||
|
}
|
||||||
|
if (!current_path_.empty()) {
|
||||||
|
std::cout << "[RECORD] Discarding: " << current_path_ << std::endl;
|
||||||
|
std::error_code ec;
|
||||||
|
std::filesystem::remove(current_path_, ec);
|
||||||
|
current_path_.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void VideoBatchWriter::stop_and_move(int batch_number) {
|
void VideoBatchWriter::stop_and_move(int batch_number) {
|
||||||
if (writer_.isOpened()) {
|
if (writer_.isOpened()) {
|
||||||
writer_.release();
|
writer_.release();
|
||||||
@@ -126,8 +158,7 @@ void VideoBatchWriter::shutdown() {
|
|||||||
if (writer_.isOpened()) {
|
if (writer_.isOpened()) {
|
||||||
writer_.release();
|
writer_.release();
|
||||||
}
|
}
|
||||||
recording_ = false;
|
state_ = IDLE;
|
||||||
delaying_ = false;
|
|
||||||
|
|
||||||
if (!current_path_.empty()) {
|
if (!current_path_.empty()) {
|
||||||
std::string src = current_path_;
|
std::string src = current_path_;
|
||||||
|
|||||||
+11
-6
@@ -8,28 +8,33 @@ public:
|
|||||||
VideoBatchWriter(const std::string& shm_dir,
|
VideoBatchWriter(const std::string& shm_dir,
|
||||||
const std::string& output_dir,
|
const std::string& output_dir,
|
||||||
int w, int h, int fps,
|
int w, int h, int fps,
|
||||||
float delay_sec);
|
float delay_sec,
|
||||||
|
float end_delay_sec);
|
||||||
|
|
||||||
~VideoBatchWriter();
|
~VideoBatchWriter();
|
||||||
|
|
||||||
void on_new_batch(int batch_number);
|
void note_motion();
|
||||||
|
void note_ayam_detection();
|
||||||
void on_batch_closed(int batch_number);
|
void on_batch_closed(int batch_number);
|
||||||
void feed_frame(const cv::Mat& raw);
|
void feed_frame(const cv::Mat& raw);
|
||||||
void shutdown();
|
void shutdown();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void start_recording(int batch_number);
|
void start_recording();
|
||||||
|
void stop_and_delete();
|
||||||
void stop_and_move(int batch_number);
|
void stop_and_move(int batch_number);
|
||||||
void ensure_dir(const std::string& dir);
|
void ensure_dir(const std::string& dir);
|
||||||
|
|
||||||
|
enum State { IDLE, SPECULATING, CONFIRMED, STOPPING };
|
||||||
|
|
||||||
std::string shm_dir_;
|
std::string shm_dir_;
|
||||||
std::string output_dir_;
|
std::string output_dir_;
|
||||||
int w_, h_, fps_;
|
int w_, h_, fps_;
|
||||||
float delay_sec_;
|
float delay_sec_;
|
||||||
|
float end_delay_sec_;
|
||||||
|
|
||||||
bool delaying_ = false;
|
State state_ = IDLE;
|
||||||
bool recording_ = false;
|
std::chrono::steady_clock::time_point state_start_;
|
||||||
std::chrono::steady_clock::time_point delay_start_;
|
|
||||||
cv::VideoWriter writer_;
|
cv::VideoWriter writer_;
|
||||||
std::string current_path_;
|
std::string current_path_;
|
||||||
int current_batch_ = 0;
|
int current_batch_ = 0;
|
||||||
|
|||||||
Reference in new issue
Block a user