mirror of
https://github.com/kerberos-io/onvif.git
synced 2026-08-23 15:08:33 +00:00
VMD 3 is the firmware-builtin motion rule, published as tns1:RuleEngine/tnsaxis:VMD3/vmd3_video_<N>. It predates the VMD 4 ACAP and lives under RuleEngine rather than CameraApplicationPlatform, so the VMD 4 rule added in the previous commit does not cover it. Confirmed against a deployed AXIS camera: with debug logging on, its event stream emits vmd3_video_1 on every motion trigger, and every one was discarded as KindUnknown. The VMD 4 rule stays — both generations are in the field.
153 lines
6.6 KiB
Go
153 lines
6.6 KiB
Go
package stream
|
|
|
|
import "strings"
|
|
|
|
// Classify maps an ONVIF topic string to the normalized Kind. Returns
|
|
// KindUnknown when no rule matches.
|
|
//
|
|
// The classifier strips XML-namespace prefixes from each "/"-separated
|
|
// segment so it is robust to vendor namespaces (tns1:, tnsaxis:,
|
|
// tnssamsung:, ...). Matching is case-sensitive — ONVIF topics are
|
|
// case-sensitive per the spec.
|
|
//
|
|
// Sources cross-checked when building the rule set below:
|
|
// - ONVIF Topic Namespace XML
|
|
// https://www.onvif.org/onvif/ver10/topics/topicns.xml
|
|
// - ONVIF Analytics Service Spec
|
|
// https://www.onvif.org/specs/srv/analytics/ONVIF-VideoAnalytics-Service-Spec-v220.pdf
|
|
// - ONVIF Device IO Service Spec
|
|
// https://www.onvif.org/specs/srv/io/ONVIF-DeviceIo-Service-Spec.pdf
|
|
// - openvideolibs/onvif-parsers (Apache-2.0) — empirical topic table
|
|
// extracted from Home Assistant
|
|
// https://github.com/openvideolibs/onvif-parsers
|
|
func Classify(topic string) Kind {
|
|
if topic == "" {
|
|
return KindUnknown
|
|
}
|
|
canonical := canonicalizeTopic(topic)
|
|
for _, rule := range topicRules {
|
|
if strings.Contains(canonical, rule.needle) {
|
|
return rule.kind
|
|
}
|
|
}
|
|
return KindUnknown
|
|
}
|
|
|
|
// canonicalizeTopic strips the XML-namespace prefix from each
|
|
// "/"-separated segment, collapsing Avigilon's per-segment-prefixed
|
|
// form ("tns1:Device/tns1:Trigger/tns1:Relay") and the plain form
|
|
// ("tns1:Device/Trigger/Relay") to the same matchable path.
|
|
func canonicalizeTopic(topic string) string {
|
|
segments := strings.Split(topic, "/")
|
|
for i, seg := range segments {
|
|
if idx := strings.Index(seg, ":"); idx >= 0 {
|
|
segments[i] = seg[idx+1:]
|
|
}
|
|
}
|
|
return strings.Join(segments, "/")
|
|
}
|
|
|
|
// topicRules is evaluated in order — first match wins. Keep more
|
|
// specific rules ahead of broader ones. LineDetector/Crossed is
|
|
// edge-triggered (no boolean State); the decoder leaves State as
|
|
// StateUnknown for it.
|
|
var topicRules = []struct {
|
|
needle string
|
|
kind Kind
|
|
}{
|
|
// tns1:VideoSource/MotionAlarm — Profile S basic motion.
|
|
// https://www.onvif.org/ver10/topics/topicns.xml
|
|
// https://developer.axis.com/vapix/network-video/event-and-action-services/
|
|
{"VideoSource/MotionAlarm", KindMotion},
|
|
|
|
// tns1:VideoAnalytics/MotionAlarm — Bosch publishes motion under
|
|
// VideoAnalytics rather than VideoSource.
|
|
// https://media.boschsecurity.com/fs/media/pb/media/partners_1/integration_tools_1/developer/bosch-metadata-and-iva-events.pdf
|
|
{"VideoAnalytics/MotionAlarm", KindMotion},
|
|
|
|
// tns1:VideoAnalytics/tnssamsung:MotionDetection — Hanwha vendor.
|
|
// https://github.com/home-assistant/core/issues/66493
|
|
{"VideoAnalytics/MotionDetection", KindMotion},
|
|
|
|
// tns1:RuleEngine/CellMotionDetector/Motion — ONVIF Analytics
|
|
// standard cell-motion rule.
|
|
// ONVIF-VideoAnalytics-Service-Spec-v220.pdf §5.3
|
|
// https://www.hikvisioneurope.com/eu/portal/portal/Technical%20Materials/24%20How%20To/CCTV/How%20to%20solve%20third%20party%20camera%20motion%20detection%20issue.pdf
|
|
{"CellMotionDetector/Motion", KindMotion},
|
|
|
|
// tns1:RuleEngine/MotionRegionDetector/Motion — AXIS region rule.
|
|
// https://developer.axis.com/vapix/network-video/event-and-action-services/
|
|
{"MotionRegionDetector/Motion", KindMotion},
|
|
|
|
// tns1:RuleEngine/tnsaxis:VMD3/vmd3_video_<N> — AXIS VMD 3, the
|
|
// firmware-builtin predecessor of the VMD 4 ACAP. It lives under
|
|
// RuleEngine, not CameraApplicationPlatform, so the VMD rule below
|
|
// does not cover it. Still shipping on deployed cameras.
|
|
// https://developer.axis.com/vapix/network-video/event-and-action-services/
|
|
{"RuleEngine/VMD3/", KindMotion},
|
|
|
|
// AXIS ACAP motion apps with Camera<N>Profile<ID> suffixes. VMD 4 is
|
|
// the stock app shipped on the camera; the Guard suite are the
|
|
// paid analytics products. Prefix-match because of the suffix.
|
|
// https://developer.axis.com/vapix/applications/vmd4
|
|
// https://developer.axis.com/vapix/applications/motion-guard
|
|
{"CameraApplicationPlatform/VMD/", KindMotion},
|
|
{"CameraApplicationPlatform/MotionGuard/", KindMotion},
|
|
{"CameraApplicationPlatform/FenceGuard/", KindMotion},
|
|
{"CameraApplicationPlatform/LoiteringGuard/", KindMotion},
|
|
|
|
// tns1:RuleEngine/TamperDetector/Tamper — standard ONVIF tamper rule.
|
|
// ONVIF-VideoAnalytics-Service-Spec-v220.pdf §5.5
|
|
{"TamperDetector/Tamper", KindTampering},
|
|
|
|
// tns1:VideoSource/GlobalSceneChange/ImagingService — the proper
|
|
// lens-cover signal on firmwares without TamperDetector.
|
|
// https://www.onvif.org/ver10/topics/topicns.xml
|
|
{"GlobalSceneChange", KindTampering},
|
|
|
|
// tns1:VideoAnalytics/tnssamsung:TamperingDetection — Hanwha.
|
|
// https://github.com/home-assistant/core/issues/66493
|
|
{"VideoAnalytics/TamperingDetection", KindTampering},
|
|
|
|
// VideoSource/ImageToo* — imaging-quality alarms. See KindImageQuality
|
|
// for the rationale on splitting these out from KindTampering.
|
|
// https://www.onvif.org/ver10/topics/topicns.xml
|
|
{"VideoSource/ImageTooDark", KindImageQuality},
|
|
{"VideoSource/ImageTooBright", KindImageQuality},
|
|
{"VideoSource/ImageTooBlurry", KindImageQuality},
|
|
|
|
// tns1:Device/Trigger/DigitalInput — standard. Avigilon's per-segment-
|
|
// prefixed serialisation ("tns1:Device/tns1:Trigger/tns1:DigitalInput")
|
|
// folds to the same canonical path.
|
|
// ONVIF-DeviceIo-Service-Spec.pdf §5.2
|
|
{"Trigger/DigitalInput", KindDigitalInput},
|
|
// ONVIF-DeviceIo-Service-Spec.pdf §5.3
|
|
{"Trigger/Relay", KindDigitalOutput},
|
|
|
|
// tnsaxis:CameraApplicationPlatform/ObjectAnalytics/Device1Scenario<N>
|
|
// — Scenario suffixes are numeric per AOA configuration. Prefix-match
|
|
// because of the dynamic suffix.
|
|
// https://developer.axis.com/analytics/axis-object-analytics/how-to-guides/axis-object-analytics-counting-data/
|
|
{"ObjectAnalytics/", KindObjectDetected},
|
|
|
|
// ONVIF-VideoAnalytics-Service-Spec-v220.pdf §5.4
|
|
{"LineDetector/Crossed", KindObjectDetected},
|
|
{"FieldDetector/ObjectsInside", KindObjectDetected},
|
|
|
|
// tns1:RuleEngine/MyRuleDetector/<RuleName> — vendor rules under the
|
|
// ONVIF MyRuleDetector container. Explicitly whitelisted because the
|
|
// same container also carries non-object rules (Bosch Counter,
|
|
// Occupancy) that must not classify as ObjectDetected.
|
|
// https://media.boschsecurity.com/fs/media/pb/media/partners_1/integration_tools_1/developer/bosch-metadata-and-iva-events.pdf
|
|
{"MyRuleDetector/HumanDetect", KindObjectDetected},
|
|
{"MyRuleDetector/VehicleDetect", KindObjectDetected},
|
|
{"MyRuleDetector/PeopleDetect", KindObjectDetected},
|
|
{"MyRuleDetector/ObjectsInside", KindObjectDetected},
|
|
{"MyRuleDetector/FaceDetect", KindObjectDetected},
|
|
|
|
{"Audio/DetectedSound", KindAudioAlarm},
|
|
// https://developer.axis.com/vapix/network-video/event-and-action-services/
|
|
{"AudioSource/TriggerLevel", KindAudioAlarm},
|
|
{"AudioAnalytics/SoundDetection", KindAudioAlarm},
|
|
}
|