File sources now keep STATE_FILE on graceful shutdown (EOF or SIGTERM): the final batch snapshot is written instead of deleted, so the dashboard's /api/current-batch still shows the recount result after the process exits. On startup, STATE_FILE is cleared unless a live instance is detected via a /proc cmdline scan (rtsp/http source in argv or config). Live sources keep the old resume-at-start / delete-on-finish behavior. SPEC: V19, T21, B2. AGENTS: STATE_FILE lifecycle section.
5.2 KiB
AGENTS.md — ByteTrack Counter C++
RKNN Dynamic Shape Requirement
The RKNN model (zenai_apc_cicalengka_20260609.rknn) is exported with dynamic input shapes (model inference type: dynamic_shape). The C API requires calling rknn_set_input_shapes() before rknn_inputs_set(). Without it, librknnrt.so crashes with:
std::out_of_range: vector::_M_range_check: __n (which is 18446744073709551615) >= this->size() (which is 1)
This is called in the constructor of RKNNYOLO at src/rknn_yolo.cpp:60, right after querying input attributes:
in_attr.dims[0] = 1;
in_attr.dims[1] = imgsz_;
in_attr.dims[2] = imgsz_;
in_attr.dims[3] = 3;
in_attr.n_dims = 4;
ret = rknn_set_input_shapes(rknn_ctx_, io_num.n_input, &in_attr);
Build
cd /opt/bytetrack-counter-cpp/build
cmake .. -DHAS_RKNN=ON
make -j$(nproc)
Service
systemctl restart bytetrack-counter
journalctl -u bytetrack-counter -f
Reset via .reset file
Place a .reset file in SHM_DIR (default /dev/shm/bytetrack-counter) to trigger a full state reset:
- Startup: deleting
.resetbefore service starts clears all state files on boot - Runtime: dropping
.resetwhile service runs callsBatchStore::reset()— ends active batch, clears in-memory state, deletesSTATE_FILE, clears live stream JPEG + writes blank frame on next write
touch /dev/shm/bytetrack-counter/.reset
STATE_FILE lifecycle (file sources)
For local file input, STATE_FILE persists the recount result so the dashboard's
/api/current-batch still shows the final batch after the process exits:
- Start: STATE_FILE is deleted unless a live instance is running — detected by
a
/proc/*/cmdlinescan for anotherbytetrack-counterwhose source isrtsp:///http://(argv orSOURCE=in its config). If live is active, the file is kept and a[INFO] Live instance active — keeping STATE_FILEline is logged. Stop the live service before recounting so stale recount state is cleared. - Finish: on graceful shutdown (
end_batch("shutdown")— EOF or SIGTERM) the final batch snapshot is written to STATE_FILE (in both the persist and the discard-below-minimum paths) instead of being deleted. - Live sources are unchanged: resume at start, delete on finish.
Shared memory
SHM_DIR (/dev/shm/bytetrack-counter by default) stores:
LIVE_STREAM_FRAME_PATHJPEG snapshotRECORD_SHM_DIRvideo recordings before move to disk.resettrigger file
Directory auto-created at startup.
Video recordings
- Recordings are written to
SHM_DIRasbatch_pending_*.mp4, confirmed when ayam detected, and moved viafork()(non-blocking) toOUTPUT_DIR/<batch counting_date>/batch_<num>_<YYYYMMDD>_<HHMMSS>.mp4. - Live sources: recording speculates (SPECULATING) and is discarded after
RECORD_DELAY_SECONDSif no ayam confirms; only CONFIRMED/STOPPING recordings are saved. - File sources (
file_source_flag): recording opens at frame 0, is never discarded by the SPECULATING timer, and any active recording is saved on batch close and on shutdown — so the output's first frame matches the source mp4's frame 0 (noRECORD_DELAYoffset). feed_frameis called every frame (outside the detections block), so recordings are continuous with no gaps on detection-less frames.- The day folder uses the batch counting date (today before
DAILY_CUTOFF_TIME, tomorrow after), forwarded fromBatchStorethrough the batch-closed callback — matching the SQLitecounting_date. - Retention cleanup compares day folders with
std::localtimeto match folder naming. - H.264 encode quality is set via
RECORD_CRF(lower = better, default unset) andRECORD_PRESET—start_recording()writesOPENCV_FFMPEG_WRITE_OPTIONS(crf;<n>|preset;<p>) beforewriter_.open().
Source override
bytetrack-counter <config.env> --source /tmp/test.mp4 # local file (single pass)
bytetrack-counter <config.env> --source rtsp://cam:554/x # live stream
bytetrack-counter <config.env> -s path # or --source=path
Capture setup (open_capture in src/main.cpp):
- Live sources:
CAP_PROP_BUFFERSIZE=1is set (reconnect-agnostic). - File sources:
CAP_PROP_POS_FRAMES=0is set — the decoder is forced to frame 0. Never setCAP_PROP_BUFFERSIZEon a file: it makes OpenCV's FFMPEG build buffer land mid-file and the first decoded frame ≠ source frame 0 (e.g. the pause-on-first-frame view showed a ~11s-later camera clock). - First successful read logs one INFO line with
pos_frames,pos_msec,frame_count,fps—pos_msec=0⇒ frame 0 is the true first frame.
Pause on first frame (file sources)
For local file input, hold the first frame as the live stream view until signalled:
- Enable via
--pause-on-first-frame(CLI, overrides env) orPAUSE_ON_FIRST_FRAME=true. - Frame 0 is fully processed (inference, tracking, HUD) then the loop idles: the annotated
frame is re-written to
LIVE_STREAM_FRAME_PATHwhile polling forSHM_DIR/.continue. - Resume by
touch /dev/shm/bytetrack-counter/.continue(file is deleted on consume). - Ignored for live (rtsp/http) sources with a warning. A stale
.continueis cleared at startup.