Phase 7 #190: zone-filter в Frigate MQTT subscriber

Frigate 0.17 schema отвергает objects.filters.<obj>.required_zones
("Extra inputs not permitted" → safe mode), поэтому фильтрацию по зонам
делаем на стороне composer'а. cfc_overlay_detbox_match_zones() сверяет
after.current_zones события с whitelist'ом overlay'я. end-события
вызываются безусловно (no-op если рамки нет).

CLI: --detection-cell key,camera,dx,dy,dw,dh,detect_w,detect_h[,zone1:zone2:...]
9-е поле опционально (colon-separated). Без него filter выключен.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-03 16:18:56 +01:00
parent 17261377cb
commit ac86534769
4 changed files with 125 additions and 8 deletions
+42 -7
View File
@@ -126,13 +126,21 @@ int main(int argc, char **argv)
const char *frigate_mqtt_host = NULL;
int frigate_mqtt_port = 1883;
const char *frigate_topic = "frigate/events";
/* --detection-cell key,camera,dx,dy,dw,dh,detect_w,detect_h
/* --detection-cell key,camera,dx,dy,dw,dh,detect_w,detect_h[,zone1:zone2:...]
* key — символьное имя для логов (например "parking")
* camera — Frigate camera_key для MQTT match'а ("parking_overview")
* dx,dy,dw,dh — координаты ячейки composer'а на output frame
* detect_w,detect_h — Frigate detect.{width,height} (640,480) */
* detect_w,detect_h — Frigate detect.{width,height} (640,480)
* zones (опц.) — colon-separated whitelist; если задан, события вне
* этих зон отбрасываются subscriber'ом (zone-filter
* заменяет Frigate-side objects.filters.required_zones
* который не работает в 0.17 schema). */
#define DETCELL_ZONE_MAX 8
typedef struct { char key[32], camera[48];
int dx, dy, dw, dh, detect_w, detect_h; } detcell_t;
int dx, dy, dw, dh, detect_w, detect_h;
char zone_storage[DETCELL_ZONE_MAX][32];
const char *zone_ptrs[DETCELL_ZONE_MAX];
int num_zones; } detcell_t;
detcell_t detcells[MAX_CELLS] = { 0 };
int num_detcells = 0;
@@ -217,7 +225,7 @@ int main(int argc, char **argv)
case 'T': frigate_topic = optarg; break;
case 'D': {
if (num_detcells >= MAX_CELLS) { fprintf(stderr, "max %d detcells\n", MAX_CELLS); return 1; }
char buf[256]; strncpy(buf, optarg, sizeof(buf) - 1); buf[sizeof(buf)-1] = '\0';
char buf[512]; strncpy(buf, optarg, sizeof(buf) - 1); buf[sizeof(buf)-1] = '\0';
char *p = buf, *q;
q = strchr(p, ','); if (!q) { fprintf(stderr, "bad --detection-cell\n"); return 1; }
*q = '\0'; strncpy(detcells[num_detcells].key, p, 31); p = q + 1;
@@ -233,7 +241,28 @@ int main(int argc, char **argv)
*q = '\0'; detcells[num_detcells].dh = atoi(p); p = q + 1;
q = strchr(p, ','); if (!q) { fprintf(stderr, "bad --detection-cell\n"); return 1; }
*q = '\0'; detcells[num_detcells].detect_w = atoi(p); p = q + 1;
detcells[num_detcells].detect_h = atoi(p);
/* detect_h — может быть последним полем или иметь ',<zones>' после. */
q = strchr(p, ',');
if (q) {
*q = '\0'; detcells[num_detcells].detect_h = atoi(p); p = q + 1;
/* Парсим zones — colon-separated whitelist. */
detcells[num_detcells].num_zones = 0;
char *z = p;
while (z && *z && detcells[num_detcells].num_zones < DETCELL_ZONE_MAX) {
char *sep = strchr(z, ':');
int len = sep ? (int)(sep - z) : (int)strlen(z);
if (len > 31) len = 31;
int idx = detcells[num_detcells].num_zones;
memcpy(detcells[num_detcells].zone_storage[idx], z, len);
detcells[num_detcells].zone_storage[idx][len] = '\0';
detcells[num_detcells].zone_ptrs[idx] =
detcells[num_detcells].zone_storage[idx];
detcells[num_detcells].num_zones++;
z = sep ? sep + 1 : NULL;
}
} else {
detcells[num_detcells].detect_h = atoi(p);
}
num_detcells++;
break;
}
@@ -415,6 +444,8 @@ int main(int argc, char **argv)
.color_y = 210, .color_u = 50, .color_v = 100, /* кислотно-зелёный */
.alpha = 240,
.stale_ms = 8000,
.required_zones = detcells[i].num_zones ? detcells[i].zone_ptrs : NULL,
.required_zones_count = detcells[i].num_zones,
};
if (cfc_overlay_create_detection_boxes(&dc, &detbox_overlays[i]) != 0) {
fprintf(stderr, "[grid_record] detbox create failed для '%s'\n",
@@ -422,10 +453,14 @@ int main(int argc, char **argv)
continue;
}
cfc_composer_add_overlay(comp, detbox_overlays[i]);
fprintf(stderr, "[grid_record] detbox '%s' → cell %s (%d,%d %dx%d), detect %dx%d\n",
fprintf(stderr, "[grid_record] detbox '%s' → cell %s (%d,%d %dx%d), detect %dx%d, zones=%d",
detcells[i].camera, detcells[i].key,
detcells[i].dx, detcells[i].dy, detcells[i].dw, detcells[i].dh,
detcells[i].detect_w, detcells[i].detect_h);
detcells[i].detect_w, detcells[i].detect_h,
detcells[i].num_zones);
for (int z = 0; z < detcells[i].num_zones; z++)
fprintf(stderr, " %s", detcells[i].zone_storage[z]);
fprintf(stderr, "\n");
}
/* Frigate MQTT subscriber (если задан --frigate-mqtt). */