Reset Mechanism
This commit is contained in:
1 parent
5eb122f422
commit
428f2a1140
8 files changed
+3315
-27
No files matched your search
+3230
-6
File diff suppressed because it is too large.
Load diff
Binary file not shown.
+5
-2
@@ -140,8 +140,11 @@ OUTPUT_FPS=15
|
|||||||
RECORD_DELAY_SECONDS=10
|
RECORD_DELAY_SECONDS=10
|
||||||
# Extra seconds to keep recording after batch end signal before stopping
|
# Extra seconds to keep recording after batch end signal before stopping
|
||||||
RECORD_END_DELAY=1
|
RECORD_END_DELAY=1
|
||||||
# Shared memory directory for recording (fast write, moved to OUTPUT_DIR on close)
|
# Days to keep recorded video folders (folders older than this deleted on startup)
|
||||||
RECORD_SHM_DIR=/dev/shm/bytetrack-counter
|
RECORD_RETENTION_DAYS=3
|
||||||
|
# Shared memory directory — used for video recording, live snapshots, and .reset trigger
|
||||||
|
# RECORD_SHM_DIR is an alias; SHM_DIR takes priority if both set
|
||||||
|
SHM_DIR=/dev/shm/bytetrack-counter
|
||||||
|
|
||||||
# --- Live stream snapshot ---
|
# --- Live stream snapshot ---
|
||||||
# Periodically write the latest annotated frame as JPEG for an external web server
|
# Periodically write the latest annotated frame as JPEG for an external web server
|
||||||
|
|||||||
+4
-1
@@ -144,7 +144,10 @@ void AppConfig::load_from_env(const char* env_path) {
|
|||||||
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");
|
auto reds_s = get_env("RECORD_END_DELAY");
|
||||||
if (!reds_s.empty()) record_end_delay_seconds = std::stof(reds_s);
|
if (!reds_s.empty()) record_end_delay_seconds = std::stof(reds_s);
|
||||||
record_shm_dir = get_env("RECORD_SHM_DIR", record_shm_dir);
|
auto rret_s = get_env("RECORD_RETENTION_DAYS");
|
||||||
|
if (!rret_s.empty()) record_retention_days = std::stoi(rret_s);
|
||||||
|
shm_dir = get_env("RECORD_SHM_DIR", shm_dir);
|
||||||
|
shm_dir = get_env("SHM_DIR", shm_dir);
|
||||||
|
|
||||||
auto lse_s = get_env("LIVE_STREAM_ENABLED");
|
auto lse_s = get_env("LIVE_STREAM_ENABLED");
|
||||||
live_stream_enabled = (lse_s == "true");
|
live_stream_enabled = (lse_s == "true");
|
||||||
|
|||||||
+2
-1
@@ -63,7 +63,8 @@ struct AppConfig {
|
|||||||
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;
|
float record_end_delay_seconds = 1.0f;
|
||||||
std::string record_shm_dir = "/dev/shm/bytetrack-counter";
|
int record_retention_days = 3;
|
||||||
|
std::string shm_dir = "/dev/shm/bytetrack-counter";
|
||||||
|
|
||||||
bool live_stream_enabled = false;
|
bool live_stream_enabled = false;
|
||||||
std::string live_stream_frame_path = "/dev/shm/bytetrack-counter/live_frame.jpg";
|
std::string live_stream_frame_path = "/dev/shm/bytetrack-counter/live_frame.jpg";
|
||||||
|
|||||||
+17
-3
@@ -141,6 +141,16 @@ int main(int argc, char* argv[]) {
|
|||||||
<< " buffer=" << g_config.track_buffer_1
|
<< " buffer=" << g_config.track_buffer_1
|
||||||
<< " min_hits=" << g_config.track_min_hits_1 << std::endl;
|
<< " min_hits=" << g_config.track_min_hits_1 << std::endl;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::string reset_file = g_config.shm_dir + "/.reset";
|
||||||
|
if (std::filesystem::exists(reset_file)) {
|
||||||
|
std::cout << "[RESET] .reset detected — clearing state" << std::endl;
|
||||||
|
std::error_code ec;
|
||||||
|
std::filesystem::remove(g_config.state_file, ec);
|
||||||
|
std::filesystem::remove(reset_file, ec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (g_config.live_stream_enabled) {
|
if (g_config.live_stream_enabled) {
|
||||||
std::filesystem::path live_p(g_config.live_stream_frame_path);
|
std::filesystem::path live_p(g_config.live_stream_frame_path);
|
||||||
if (live_p.has_parent_path())
|
if (live_p.has_parent_path())
|
||||||
@@ -223,10 +233,11 @@ int main(int argc, char* argv[]) {
|
|||||||
std::unique_ptr<VideoBatchWriter> video_writer;
|
std::unique_ptr<VideoBatchWriter> video_writer;
|
||||||
if (g_config.record_video) {
|
if (g_config.record_video) {
|
||||||
video_writer = std::make_unique<VideoBatchWriter>(
|
video_writer = std::make_unique<VideoBatchWriter>(
|
||||||
g_config.record_shm_dir, g_config.output_dir,
|
g_config.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);
|
g_config.record_end_delay_seconds,
|
||||||
|
g_config.record_retention_days);
|
||||||
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); });
|
||||||
}
|
}
|
||||||
@@ -256,7 +267,8 @@ int main(int argc, char* argv[]) {
|
|||||||
std::chrono::steady_clock::now() - session_start).count();
|
std::chrono::steady_clock::now() - session_start).count();
|
||||||
auto mono = std::chrono::steady_clock::now();
|
auto mono = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
if (g_config.reset_counters_at_cutoff && store.check_cutoff_reset()) {
|
if (store.check_cutoff_reset()) {
|
||||||
|
if (g_config.reset_counters_at_cutoff) {
|
||||||
std::cout << "[" << now_str() << "] Cutoff reset — resetting frame + tracker counters" << std::endl;
|
std::cout << "[" << now_str() << "] Cutoff reset — resetting frame + tracker counters" << std::endl;
|
||||||
frame_idx = 0;
|
frame_idx = 0;
|
||||||
KalmanBoxTracker::count = 0;
|
KalmanBoxTracker::count = 0;
|
||||||
@@ -273,6 +285,8 @@ int main(int argc, char* argv[]) {
|
|||||||
count_pulse = 0;
|
count_pulse = 0;
|
||||||
batch_pulse = 0;
|
batch_pulse = 0;
|
||||||
}
|
}
|
||||||
|
if (video_writer) video_writer->cleanup_retention();
|
||||||
|
}
|
||||||
|
|
||||||
bool ayam_crossed_frame = false, batch_closed_frame = false, batch_started_frame = false;
|
bool ayam_crossed_frame = false, batch_closed_frame = false, batch_started_frame = false;
|
||||||
|
|
||||||
|
|||||||
+53
-13
@@ -8,31 +8,68 @@
|
|||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
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)
|
float end_delay_sec,
|
||||||
|
int retention_days)
|
||||||
: shm_dir_(shm_dir), output_dir_(output_dir),
|
: shm_dir_(shm_dir), output_dir_(output_dir),
|
||||||
w_(w), h_(h), fps_(fps),
|
w_(w), h_(h), fps_(fps),
|
||||||
delay_sec_(delay_sec), end_delay_sec_(end_delay_sec)
|
delay_sec_(delay_sec), end_delay_sec_(end_delay_sec),
|
||||||
|
retention_days_(retention_days)
|
||||||
{
|
{
|
||||||
ensure_dir(shm_dir_);
|
ensure_dir(shm_dir_);
|
||||||
ensure_dir(output_dir_);
|
ensure_dir(output_dir_);
|
||||||
|
|
||||||
for (const auto& entry : std::filesystem::directory_iterator(shm_dir_)) {
|
for (const auto& entry : fs::directory_iterator(shm_dir_)) {
|
||||||
if (entry.path().extension() == ".mp4") {
|
if (entry.path().extension() == ".mp4") {
|
||||||
std::filesystem::remove(entry.path());
|
fs::remove(entry.path());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cleanup_retention();
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoBatchWriter::~VideoBatchWriter() {
|
VideoBatchWriter::~VideoBatchWriter() {
|
||||||
shutdown();
|
shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VideoBatchWriter::cleanup_retention() {
|
||||||
|
auto cutoff = std::chrono::system_clock::now() - std::chrono::hours(retention_days_ * 24);
|
||||||
|
auto cutoff_t = std::chrono::system_clock::to_time_t(cutoff);
|
||||||
|
std::ostringstream cutoff_ss;
|
||||||
|
cutoff_ss << std::put_time(std::gmtime(&cutoff_t), "%Y-%m-%d");
|
||||||
|
std::string cutoff_str = cutoff_ss.str();
|
||||||
|
|
||||||
|
for (const auto& entry : fs::directory_iterator(output_dir_)) {
|
||||||
|
if (!entry.is_directory()) continue;
|
||||||
|
std::string dirname = entry.path().filename().string();
|
||||||
|
if (dirname < cutoff_str) {
|
||||||
|
std::error_code ec;
|
||||||
|
fs::remove_all(entry.path(), ec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void VideoBatchWriter::ensure_dir(const std::string& dir) {
|
void VideoBatchWriter::ensure_dir(const std::string& dir) {
|
||||||
std::filesystem::create_directories(dir);
|
fs::create_directories(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string today_str() {
|
||||||
|
auto t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
|
||||||
|
std::ostringstream ss;
|
||||||
|
ss << std::put_time(std::localtime(&t), "%Y-%m-%d");
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string timestamp_str() {
|
||||||
|
auto t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
|
||||||
|
std::ostringstream ss;
|
||||||
|
ss << std::put_time(std::localtime(&t), "%H%M%S");
|
||||||
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoBatchWriter::note_motion() {
|
void VideoBatchWriter::note_motion() {
|
||||||
@@ -114,7 +151,7 @@ static void copy_and_clean(const std::string& src, const std::string& dst) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
std::filesystem::remove(src, ec);
|
fs::remove(src, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoBatchWriter::stop_and_delete() {
|
void VideoBatchWriter::stop_and_delete() {
|
||||||
@@ -124,7 +161,7 @@ void VideoBatchWriter::stop_and_delete() {
|
|||||||
if (!current_path_.empty()) {
|
if (!current_path_.empty()) {
|
||||||
std::cout << "[RECORD] Discarding: " << current_path_ << std::endl;
|
std::cout << "[RECORD] Discarding: " << current_path_ << std::endl;
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
std::filesystem::remove(current_path_, ec);
|
fs::remove(current_path_, ec);
|
||||||
current_path_.clear();
|
current_path_.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,11 +175,12 @@ void VideoBatchWriter::stop_and_move(int batch_number) {
|
|||||||
std::string src = current_path_;
|
std::string src = current_path_;
|
||||||
current_path_.clear();
|
current_path_.clear();
|
||||||
|
|
||||||
auto t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
|
std::string day_dir = output_dir_ + "/" + today_str();
|
||||||
|
ensure_dir(day_dir);
|
||||||
|
|
||||||
std::ostringstream name;
|
std::ostringstream name;
|
||||||
name << "batch_" << batch_number << "_"
|
name << "batch_" << batch_number << "_" << timestamp_str() << ".mp4";
|
||||||
<< std::put_time(std::localtime(&t), "%Y%m%d_%H%M%S") << ".mp4";
|
std::string dst = day_dir + "/" + name.str();
|
||||||
std::string dst = output_dir_ + "/" + name.str();
|
|
||||||
|
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
@@ -162,8 +200,10 @@ void VideoBatchWriter::shutdown() {
|
|||||||
|
|
||||||
if (!current_path_.empty()) {
|
if (!current_path_.empty()) {
|
||||||
std::string src = current_path_;
|
std::string src = current_path_;
|
||||||
std::string dst = output_dir_ + "/" +
|
std::string day_dir = output_dir_ + "/" + today_str();
|
||||||
std::filesystem::path(current_path_).filename().string();
|
ensure_dir(day_dir);
|
||||||
|
std::string dst = day_dir + "/" +
|
||||||
|
fs::path(current_path_).filename().string();
|
||||||
current_path_.clear();
|
current_path_.clear();
|
||||||
|
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ public:
|
|||||||
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);
|
float end_delay_sec,
|
||||||
|
int retention_days);
|
||||||
|
|
||||||
~VideoBatchWriter();
|
~VideoBatchWriter();
|
||||||
|
|
||||||
@@ -17,6 +18,7 @@ public:
|
|||||||
void note_ayam_detection();
|
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 cleanup_retention();
|
||||||
void shutdown();
|
void shutdown();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -32,6 +34,7 @@ private:
|
|||||||
int w_, h_, fps_;
|
int w_, h_, fps_;
|
||||||
float delay_sec_;
|
float delay_sec_;
|
||||||
float end_delay_sec_;
|
float end_delay_sec_;
|
||||||
|
int retention_days_;
|
||||||
|
|
||||||
State state_ = IDLE;
|
State state_ = IDLE;
|
||||||
std::chrono::steady_clock::time_point state_start_;
|
std::chrono::steady_clock::time_point state_start_;
|
||||||
|
|||||||
Reference in new issue
Block a user