JSI · Physical Security Engineering · Project EGA

Event Gateway

EGA takes the detection events a camera already produces and turns them into something the CenterV2 operator can see — a box drawn on the live video itself. This is the working logbook: what we learned, what we measured, what we changed, and what is still open.

Project
EGA
Owner
Luis Huerta
Opened
2026-08-16
Updated
2026-08-19
Phase
Pilot running
Pilot camera
172.16.0.36

1Objective

Between 18:00 and 06:00, when a Dahua camera detects a person or a vehicle, the CenterV2 monitoring agent should see a bounding box drawn on the live video.

The constraint that shapes every decision below: CenterV2 will not render third-party metadata. Any design that ships box coordinates alongside the video and hopes the client draws them is dead on arrival.

The box has to be in the pixels. Once it is in the pixels it survives GeoVision, the forward to CenterV2, and the recording — nothing downstream has to understand it.

2Where the project stands

No Can the camera do it alone

Settled with a full config dump. The overlay node simply does not exist on this hardware.

5.3% CPU per camera, hardware encode

One core's worth covers roughly 18 cameras. The video path is affordable.

200× RAM saved by buffering packets

18 MB instead of 4 GB across twelve cameras. This decides the trailer hardware.

ItemStateNote
Camera can burn boxes itselfRuled outEvidence in §4.1
Box coordinate formatConfirmedVerified arithmetically against a live event
Pilot recorderRunningBuilt and tested 2026-08-19
Live RTSP proxyDesignedNot built yet
GeoVision integrationNot startedGeneric RTSP confirmed accepted

Open questions

QuestionWhy it mattersBlocking
GeoVision channel licensing The recommended design needs two channels per camera. At 12 cameras that is 24. Needs answer
Substream keyframe interval Currently one every 4 seconds. GeoVision would show black on connect, which reads as a dead camera. Needs approval
MediaMTX download Required to serve the RTSP stream the proxy produces. Needs approval
Email alerting Deferred by the operator. No credentials stored anywhere. Parked

3Architecture decisions

3.1  A re-encoding proxy is required

Two approaches were rejected. Having the camera burn the boxes is not supported on this hardware (§4.1). Shipping metadata to CenterV2 fails because it will not render it.

Accepted: decode the camera substream, draw, re-encode, republish as RTSP. GeoVision accepts a generic RTSP source, which makes this clean to wire up.

Dahua substream (RTSP) ↓ decode Draw the boxesraw frames ffmpegh264_qsvpublish MediaMTX  →  GeoVision pulls rtsp://proxy:8554/cam36

3.2  Two GeoVision channels per camera

Channel A connects straight to the camera mainstream and is what records. Evidence stays clean, with no synthetic annotation burned into it, and if the proxy dies the recording is untouched. Channel B carries the proxy output and is the only channel mapped to CenterV2 for live view.

The cost is double the channel count. The alternative — a single channel through the proxy — puts synthetic marks into evidence video and makes the proxy a single point of failure for evidence. That trade is a management call, not an engineering default.

3.3  The live proxy has to encode continuously

Corrects an earlier assumption

The clip recorder can sleep when the scene is empty. The live proxy cannot: a VMS treats a stream that stops as a failed camera and raises an alarm. Decode plus encode is a permanent floor whenever the proxy is up, not an event-triggered cost.

The obvious optimization — pass the stream through untouched while idle and only re-encode during detections — does not work. Switching codecs mid-session changes the stream headers and breaks timestamp continuity, so the client disconnects. That is exactly the failure we were trying to avoid.

3.4  The box the operator sees comes from our detector, not the camera

The camera's metadata is event-shaped, not track-shaped (§4.3). It cannot produce a box that follows a person across frames. It is valuable as a trigger — "look here now" — but the box drawn on screen should come from the verified Hailo detector.

Drawing unverified camera boxes would give false positives visual legitimacy on the operator's screen. That could make alert quality worse, not better, which is the opposite of the point.

3.5  Trailer hardware: video plumber, not brain

The Intel N150 has four efficiency cores and Quick Sync. It handles the video path if we use hardware encoding rather than software (§5.2). It cannot run continuous neural detection for several cameras — no usable NPU, weak integrated graphics. Boxes have to arrive from the camera or from the Hailo box over the network.

4Research findings

Everything below came from device 172.16.0.36 — an IPC-HFW5442E-Z4E on firmware 2.840.0000000.13.R, build 2022-01-10.

4.1  The camera cannot burn boxes into the encoded stream Confirmed

A full read of the camera's overlay configuration returns only channel title, timestamp, custom titles, privacy masks, the PTZ on-screen displays, temperature and voltage. There is no rule-overlay or target-overlay node, so there is no flag to switch on for detection boxes.

This explains something worth internalizing: the green boxes visible in the Dahua web interface are not in the video. The browser draws them from a parallel metadata feed. The pixels never carried them, which is why GeoVision has never shown them and why no camera setting will produce them.

Not yet verified

Whether a newer WizSense S3/S5 model behaves differently. Worth one check before treating this as a fleet-wide rule.

4.2  Box coordinate format Confirmed

Boxes arrive as corners — not position-plus-size — in Dahua's normalized 0–8192 space rather than pixels. This was verified, not inferred: the payload's own center field is exactly the midpoint of the box it ships with.

SourceFieldFormatSpace
Camera tripwireObject.BoundingBox[x1, y1, x2, y2]0–8192
Camera smart motionobject[].Rect[x1, y1, x2, y2]0–8192
Frigate HTTP APIdata.box[x, y, w, h]0–1
Frigate MQTTafter.box[x1, y1, x2, y2]pixels

The two camera sources disagree with each other. For the same tracked object they reported different rectangles — different detectors, different instants. They must never be averaged or mixed.

These are the third and fourth box formats in the wider Jatagan work. Confusing formats has already produced one false conclusion on the AI Box project, so the rule now is to name the source before reasoning about any box.

4.3  What the metadata does not contain Confirmed

Across four real tripwire events:

  • No confidence score. The field is present but always zero. There is nothing to threshold on.
  • No trajectory. The track array is empty every time.
  • No tracking. The start and stop events carry the identical frozen rectangle. It is a snapshot at the moment of crossing, not a box that follows anyone.

This is what forces decision 3.4.

4.4  Timestamps align to the millisecond Confirmed

Each event carries a presentation timestamp that correlates with the payload clock to within a few milliseconds across sampled pairs. This is the mechanism for placing a box on its exact frame without guessing at network latency.

4.5  Traps worth writing down

TrapConsequenceStatus
The smart-motion object ID field is misspelled in the firmware The parser has to misspell it too, deliberately Confirmed
The event clock field appears to carry local time dressed as UTC Reading it as true UTC would shift alignment by whole hours Inferred — calibrate
Command-line tooling treats array indices in a URL as wildcards A configuration write silently failed and returned an empty body Confirmed & solved

4.6  Side findings on the tripwire rules

Outside this project's scope, but observed in the same captures and directly affecting alert quality, so recorded here rather than lost.

  • The active rule carries eight vertices for what should be a two-point tripwire, with the last two jumping back across the scene. The camera evaluates all eight.
  • Observed consequence: two different people each triggered two crossings in opposite directions about two seconds apart. Two out of two. Every person crossing that rule may be generating two alerts. The fix is redrawing the tripwire in the camera, not in code.
  • Both active rules have no size filtering at all, so a two-pixel object at the back of the scene qualifies the same as a person at ten meters.

5Measurements

All taken on the engineering workstation (28 cores) against the pilot camera, D1 substream. The trailer hardware is weaker, so these are ratios to scale from, not absolute budgets.

5.1  Idle path — listener plus rolling frame buffer

Substream rateOne cameraTwelve cameras
30 fps2.3% of a core0.27 cores
15 fps1.4% of a core0.16 cores

The drop is not exactly half because the event connection costs the same either way.

5.2  Encoder benchmark — one camera, D1 at 15 fps

PathCPUTwelve cameras, always on
Pass through, no decode0.26% of a core0.03 cores
Software encode7.6%0.91 cores
Hardware encode (Quick Sync)5.3%0.64 cores

NVIDIA encoding is compiled into our ffmpeg but unusable on this workstation — there is no NVIDIA GPU in it. On the N150 expect software encoding to scale far worse and Quick Sync to hold roughly steady, since it is a dedicated block rather than general-purpose cores.

5.3  Memory — the twelve-second pre-roll buffer

A clip has to start before the trigger, otherwise the video begins after the subject has already walked into frame. That means keeping recent video in memory at all times. How we keep it is the single most consequential decision for the trailer hardware.

Buffer contentsOne cameraTwelve cameras
Decoded frames at 30 fps~350 MB4.08 GB
Decoded frames at 15 fps~174 MB2.04 GB
Compressed packets~1.5 MB18 MB

A 200× difference. An N150 machine typically ships with 8–16 GB, so four gigabytes of buffers alone is not viable and two is uncomfortable. Eighteen megabytes is free.

6Change log

6.1  Changes to live equipment

DateDeviceChangeReversibleVerified
2026-08-19 172.16.0.36 Substream frame rate 30 → 15. Mainstream untouched. Yes Config re-read & stream confirmed

Nothing else on any camera, recorder or remote host has been modified by this project. Every other device interaction was read-only. The frame rate change was explicitly authorized in session; the pending keyframe change is not covered by that authorization and will be raised separately.

6.2  Local artifacts created

PathPurpose
C:\Users\lhuer\jatagan-bbox\Project root
  bbox_clip_pilot.pyThe pilot: listener, buffer, recorder, notifier
  synthetic_test.pyInjects a fake detection so the record path can be validated without waiting for a person
  measure_idle.pyIdle CPU measurement
  measure_ram.pyBuffer memory measurement
  LOGBOOK.mdFull local version of this document
C:\Users\lhuer\.jatagan\Credentials, deliberately outside any project folder so they never reach a repository
E:\jatagan-bbox-pilot\Clip output, sidecar data, run log

6.3  Defect found and fixed during the pilot

Clip frame rate was hardcoded while the live substream ran at a different rate, so clips would have played at roughly half speed. The buffer now measures the real arrival rate and writes the clip at that rate. Caught by test T5, confirmed fixed by T6.

7Corrections to earlier conclusions

Kept deliberately. Each of these was believed and acted on before being disproven, and the record is more useful with them than without.

7.1  The camera does not give us a free trajectory

An earlier note recorded that tripwire events carried the camera's own computed trajectory, described as "a free second opinion." Four real events show it empty every time. Any design leaning on camera-supplied tracking had no foundation.

7.2  Buffering compressed packets — right call, wrong reason

First stated as the top processor optimization. Then measured: continuous decoding costs 1.4% of a core, so as a processor optimization it is nearly pointless, and it was deprioritized. Then measured from the memory side, where it is a 200× difference.

It is back to priority one — as a memory decision, not a processor one. On a 28-core workstation with abundant RAM the problem is invisible. On the trailer hardware it decides whether the system runs at all.

7.3  "An empty scene costs nothing"

True for the clip recorder, false for the live proxy. See 3.3.

8Resource inventory

Workstation

ResourceDetail
Cores28
Python3.13.2 — imaging and HTTP libraries present; PyAV not installed (needed for the packet-buffer rewrite)
ffmpeg8.1.1, bundled with Jatagan Footage Editor
Encoders availableSoftware and Intel Quick Sync both working; NVIDIA present but unusable
External diskSamsung T7 Shield, 931 GB, 786 GB free

Devices

DeviceAddressNotes
Pilot camera172.16.0.36IPC-HFW5442E-Z4E, on-screen label AIC-0-36 / D2P1-184
Hailo filter PC172.16.10.61Remote shell is PowerShell 5.1. No email configuration exists there, contrary to an early assumption
GeoVision recorder172.16.11.245Accepts generic RTSP sources

Credentials are never recorded in this document.

Existing code worth reusing

Two files in the earlier snapshot project turned out to cover most of the pilot's ground. tripwire_email_notifier.py already implements the event listener, a video ring buffer, box drawing in the camera's coordinate space, and email with anti-spam throttling. ivs_watch.py contains a tuned algorithm for choosing which frame a detection belongs to — prior art on exactly the alignment problem this project has to solve.

9Test log

#DateTestResult
T108-1615 s event captureHeartbeats only. Endpoint alive, format not confirmed
T208-16100 s event captureHeartbeats only. Reported as a null result rather than rounded up
T308-169 min event captureTwo people captured. Six usable events. Sections 4.2–4.6 all come from this
T408-19Preflight checkCamera, ffmpeg, disk, RTSP all pass. Verdict READY
T508-19Synthetic clip, 30 fpsDefect found — frame rate mismatch, clip would play at half speed
T608-19Synthetic clip after fix363 frames, 11.37 s, rate measured correctly
T708-19Visual check of a drawn frameBox renders correctly; label and timestamp present; camera on-screen display intact
T808-19Idle CPU at 30 fps2.3% of a core
T908-19Camera set to 15 fps, re-measureConfirmed arriving at 15.0 fps; idle CPU 1.4%
T1008-19Synthetic clip on 15 fps stream194 frames, 11.28 s. Correct
T1108-19Encoder benchmarkSee section 5.2
T1208-19Live pilot window, real foot trafficRunning — results pending

10Next steps

  1. Review the pilot output. The question it answers is whether the box lands on the right person at the right frame — not whether we can draw one, which is already settled.
  2. If alignment holds: stand up the streaming server, build the live proxy, and prove the chain end to end into GeoVision.
  3. Shorten the substream keyframe interval before the proxy work. A VMS showing four seconds of black on connect reads as a dead camera.
  4. Confirm GeoVision channel headroom, which decides the recording architecture.
  5. Move the pre-roll buffer from decoded frames to compressed packets before anything ships to the trailer. This is the 200× memory decision.