Roadmap M2: Dahua adapter #5

Closed
opened 2026-05-27 19:37:07 +00:00 by coding-agent-marvin8 · 1 comment
coding-agent-marvin8 commented 2026-05-27 19:37:07 +00:00 (Migrated from codeberg.org)

Cang needs to understand the folder structure written by Dahua NVRs so it can locate video clips and their associated snapshot images.

Dahua NVRs organise recordings under a root directory with the camera serial as the top-level folder, then date, channel, and hour sub-directories. Video clips are .dav files; each clip has a matching set of per-second JPEG snapshots stored in a parallel jpg/ tree. Clips that recorded a motion event carry an [M] flag in the filename; the first frame of a recording sequence carries [F].

This milestone delivers the adapter layer that turns that raw folder tree into structured IncomingClip objects that the rest of the pipeline can consume, without needing to know any Dahua-specific details.

Cang needs to understand the folder structure written by Dahua NVRs so it can locate video clips and their associated snapshot images. Dahua NVRs organise recordings under a root directory with the camera serial as the top-level folder, then date, channel, and hour sub-directories. Video clips are `.dav` files; each clip has a matching set of per-second JPEG snapshots stored in a parallel `jpg/` tree. Clips that recorded a motion event carry an `[M]` flag in the filename; the first frame of a recording sequence carries `[F]`. This milestone delivers the adapter layer that turns that raw folder tree into structured `IncomingClip` objects that the rest of the pipeline can consume, without needing to know any Dahua-specific details.
coding-agent-marvin8 commented 2026-05-27 19:47:56 +00:00 (Migrated from codeberg.org)

Findings

Explored the real NVR folder tree from dahua-folders-files.txt:

  • Root: <serial>/<YYYY-MM-DD>/<channel>/dav/<HH>/<stem>.dav
  • Snapshot tree: <serial>/<YYYY-MM-DD>/<channel>/jpg/<HH>/<MM>/<SS>[flags].jpg
  • Clip stem format: HH.MM.SS-HH.MM.SS[flags][0@0][0]
    • [M] = motion event, [F] = first frame of recording sequence
    • [0@0][0] suffix is always present but carries no useful information
  • .idx sidecar files exist for every .dav — skip/ignore them
  • Snapshot times are derived from the directory path + filename (HH from dir, MM from dir, SS from stem prefix)
  • Snapshots are matched to a clip by timestamp range (clip.start <= snapshot_time <= clip.end), not by filename stem

Plan of attack

  1. src/cang/adapters/base.pyIncomingClip dataclass (path, serial, date, channel, start, end, motion, first_frame, snapshots) + BaseAdapter ABC with scan(root) -> Iterator[IncomingClip]
  2. tests/adapters/test_dahua.py — failing tests first (TDD):
    • Unit: _parse_clip_stem, _parse_snapshot_path, boundary inclusion/exclusion
    • Integration: minimal tmp_path tree, assert 2 clips yielded with correct snapshot lists
  3. src/cang/adapters/dahua.pyDahuaAdapter.scan() walks the tree, parses filenames with regex, matches snapshots per the timestamp range logic; skips .idx files

Branch: feat/issue-5-m2-dahua-adapter

## Findings Explored the real NVR folder tree from `dahua-folders-files.txt`: - Root: `<serial>/<YYYY-MM-DD>/<channel>/dav/<HH>/<stem>.dav` - Snapshot tree: `<serial>/<YYYY-MM-DD>/<channel>/jpg/<HH>/<MM>/<SS>[flags].jpg` - Clip stem format: `HH.MM.SS-HH.MM.SS[flags][0@0][0]` - `[M]` = motion event, `[F]` = first frame of recording sequence - `[0@0][0]` suffix is always present but carries no useful information - `.idx` sidecar files exist for every `.dav` — skip/ignore them - Snapshot times are derived from the directory path + filename (HH from dir, MM from dir, SS from stem prefix) - Snapshots are matched to a clip by timestamp range (`clip.start <= snapshot_time <= clip.end`), not by filename stem ## Plan of attack 1. `src/cang/adapters/base.py` — `IncomingClip` dataclass (path, serial, date, channel, start, end, motion, first_frame, snapshots) + `BaseAdapter` ABC with `scan(root) -> Iterator[IncomingClip]` 2. `tests/adapters/test_dahua.py` — failing tests first (TDD): - Unit: `_parse_clip_stem`, `_parse_snapshot_path`, boundary inclusion/exclusion - Integration: minimal `tmp_path` tree, assert 2 clips yielded with correct snapshot lists 3. `src/cang/adapters/dahua.py` — `DahuaAdapter.scan()` walks the tree, parses filenames with regex, matches snapshots per the timestamp range logic; skips `.idx` files Branch: `feat/issue-5-m2-dahua-adapter`
Sign in to join this conversation.
No labels
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
marvin8/cang#5
No description provided.