mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-12-19 19:06:16 +01:00
remove clip_ready event type
this doesnt really mean anything more than "end" anymore. new has_clip property added
This commit is contained in:
parent
86a5b46c68
commit
1b2134c49e
@ -36,7 +36,7 @@ Message published for each changed event. The first message is published when th
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "update", // new, update, end or clip_ready
|
||||
"type": "update", // new, update, end
|
||||
"before": {
|
||||
"id": "1607123955.475377-mxklsc",
|
||||
"camera": "front_door",
|
||||
@ -53,7 +53,9 @@ Message published for each changed event. The first message is published when th
|
||||
"region": [264, 450, 667, 853],
|
||||
"current_zones": ["driveway"],
|
||||
"entered_zones": ["yard", "driveway"],
|
||||
"thumbnail": null
|
||||
"thumbnail": null,
|
||||
"has_snapshot": false,
|
||||
"has_clip": false
|
||||
},
|
||||
"after": {
|
||||
"id": "1607123955.475377-mxklsc",
|
||||
@ -71,7 +73,9 @@ Message published for each changed event. The first message is published when th
|
||||
"region": [218, 440, 693, 915],
|
||||
"current_zones": ["yard", "driveway"],
|
||||
"entered_zones": ["yard", "driveway"],
|
||||
"thumbnail": null
|
||||
"thumbnail": null,
|
||||
"has_snapshot": false,
|
||||
"has_clip": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -29,38 +29,6 @@ class EventProcessor(threading.Thread):
|
||||
self.events_in_process = {}
|
||||
self.stop_event = stop_event
|
||||
|
||||
def should_create_clip(self, camera, event_data):
|
||||
if event_data["false_positive"]:
|
||||
return False
|
||||
|
||||
record_config: RecordConfig = self.config.cameras[camera].record
|
||||
|
||||
# Recording is disabled
|
||||
if not record_config.enabled:
|
||||
return False
|
||||
|
||||
# If there are required zones and there is no overlap
|
||||
required_zones = record_config.events.required_zones
|
||||
if len(required_zones) > 0 and not set(event_data["entered_zones"]) & set(
|
||||
required_zones
|
||||
):
|
||||
logger.debug(
|
||||
f"Not creating clip for {event_data['id']} because it did not enter required zones"
|
||||
)
|
||||
return False
|
||||
|
||||
# If the required objects are not present
|
||||
if (
|
||||
record_config.events.objects is not None
|
||||
and event_data["label"] not in record_config.events.objects
|
||||
):
|
||||
logger.debug(
|
||||
f"Not creating clip for {event_data['id']} because it did not contain required objects"
|
||||
)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def run(self):
|
||||
while not self.stop_event.is_set():
|
||||
try:
|
||||
@ -74,11 +42,9 @@ class EventProcessor(threading.Thread):
|
||||
self.events_in_process[event_data["id"]] = event_data
|
||||
|
||||
if event_type == "end":
|
||||
has_clip = self.should_create_clip(camera, event_data)
|
||||
|
||||
event_config: EventsConfig = self.config.cameras[camera].record.events
|
||||
|
||||
if has_clip or event_data["has_snapshot"]:
|
||||
if event_data["has_clip"] or event_data["has_snapshot"]:
|
||||
Event.create(
|
||||
id=event_data["id"],
|
||||
label=event_data["label"],
|
||||
@ -89,12 +55,12 @@ class EventProcessor(threading.Thread):
|
||||
false_positive=event_data["false_positive"],
|
||||
zones=list(event_data["entered_zones"]),
|
||||
thumbnail=event_data["thumbnail"],
|
||||
has_clip=has_clip,
|
||||
has_clip=event_data["has_clip"],
|
||||
has_snapshot=event_data["has_snapshot"],
|
||||
)
|
||||
|
||||
del self.events_in_process[event_data["id"]]
|
||||
self.event_processed_queue.put((event_data["id"], camera, has_clip))
|
||||
self.event_processed_queue.put((event_data["id"], camera))
|
||||
|
||||
logger.info(f"Exiting event processor...")
|
||||
|
||||
|
@ -16,7 +16,7 @@ from typing import Callable, Dict
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
from frigate.config import CameraConfig, FrigateConfig
|
||||
from frigate.config import CameraConfig, SnapshotsConfig, RecordConfig, FrigateConfig
|
||||
from frigate.const import CACHE_DIR, CLIPS_DIR, RECORD_DIR
|
||||
from frigate.edgetpu import load_labels
|
||||
from frigate.util import (
|
||||
@ -73,6 +73,8 @@ class TrackedObject:
|
||||
self.current_zones = []
|
||||
self.entered_zones = set()
|
||||
self.false_positive = True
|
||||
self.has_clip = False
|
||||
self.has_snapshot = False
|
||||
self.top_score = self.computed_score = 0.0
|
||||
self.thumbnail_data = None
|
||||
self.last_updated = 0
|
||||
@ -176,6 +178,8 @@ class TrackedObject:
|
||||
"region": self.obj_data["region"],
|
||||
"current_zones": self.current_zones.copy(),
|
||||
"entered_zones": list(self.entered_zones).copy(),
|
||||
"has_clip": self.has_clip,
|
||||
"has_snapshot": self.has_snapshot,
|
||||
}
|
||||
|
||||
if include_thumbnail:
|
||||
@ -611,9 +615,46 @@ class TrackedObjectProcessor(threading.Thread):
|
||||
obj.previous = after
|
||||
|
||||
def end(camera, obj: TrackedObject, current_frame_time):
|
||||
snapshot_config = self.config.cameras[camera].snapshots
|
||||
event_data = obj.to_dict(include_thumbnail=True)
|
||||
event_data["has_snapshot"] = False
|
||||
# populate has_snapshot
|
||||
obj.has_snapshot = self.should_save_snapshot(camera, obj)
|
||||
obj.has_clip = self.should_retain_recording(camera, obj)
|
||||
|
||||
# write the snapshot to disk
|
||||
if obj.has_snapshot:
|
||||
snapshot_config: SnapshotsConfig = self.config.cameras[camera].snapshots
|
||||
jpg_bytes = obj.get_jpg_bytes(
|
||||
timestamp=snapshot_config.timestamp,
|
||||
bounding_box=snapshot_config.bounding_box,
|
||||
crop=snapshot_config.crop,
|
||||
height=snapshot_config.height,
|
||||
quality=snapshot_config.quality,
|
||||
)
|
||||
if jpg_bytes is None:
|
||||
logger.warning(f"Unable to save snapshot for {obj.obj_data['id']}.")
|
||||
else:
|
||||
with open(
|
||||
os.path.join(CLIPS_DIR, f"{camera}-{obj.obj_data['id']}.jpg"),
|
||||
"wb",
|
||||
) as j:
|
||||
j.write(jpg_bytes)
|
||||
|
||||
# write clean snapshot if enabled
|
||||
if snapshot_config.clean_copy:
|
||||
png_bytes = obj.get_clean_png()
|
||||
if png_bytes is None:
|
||||
logger.warning(
|
||||
f"Unable to save clean snapshot for {obj.obj_data['id']}."
|
||||
)
|
||||
else:
|
||||
with open(
|
||||
os.path.join(
|
||||
CLIPS_DIR,
|
||||
f"{camera}-{obj.obj_data['id']}-clean.png",
|
||||
),
|
||||
"wb",
|
||||
) as p:
|
||||
p.write(png_bytes)
|
||||
|
||||
if not obj.false_positive:
|
||||
message = {
|
||||
"before": obj.previous,
|
||||
@ -623,46 +664,8 @@ class TrackedObjectProcessor(threading.Thread):
|
||||
self.client.publish(
|
||||
f"{self.topic_prefix}/events", json.dumps(message), retain=False
|
||||
)
|
||||
# write snapshot to disk if enabled
|
||||
if snapshot_config.enabled and self.should_save_snapshot(camera, obj):
|
||||
jpg_bytes = obj.get_jpg_bytes(
|
||||
timestamp=snapshot_config.timestamp,
|
||||
bounding_box=snapshot_config.bounding_box,
|
||||
crop=snapshot_config.crop,
|
||||
height=snapshot_config.height,
|
||||
quality=snapshot_config.quality,
|
||||
)
|
||||
if jpg_bytes is None:
|
||||
logger.warning(
|
||||
f"Unable to save snapshot for {obj.obj_data['id']}."
|
||||
)
|
||||
else:
|
||||
with open(
|
||||
os.path.join(
|
||||
CLIPS_DIR, f"{camera}-{obj.obj_data['id']}.jpg"
|
||||
),
|
||||
"wb",
|
||||
) as j:
|
||||
j.write(jpg_bytes)
|
||||
event_data["has_snapshot"] = True
|
||||
|
||||
# write clean snapshot if enabled
|
||||
if snapshot_config.clean_copy:
|
||||
png_bytes = obj.get_clean_png()
|
||||
if png_bytes is None:
|
||||
logger.warning(
|
||||
f"Unable to save clean snapshot for {obj.obj_data['id']}."
|
||||
)
|
||||
else:
|
||||
with open(
|
||||
os.path.join(
|
||||
CLIPS_DIR,
|
||||
f"{camera}-{obj.obj_data['id']}-clean.png",
|
||||
),
|
||||
"wb",
|
||||
) as p:
|
||||
p.write(png_bytes)
|
||||
self.event_queue.put(("end", camera, event_data))
|
||||
self.event_queue.put(("end", camera, obj.to_dict(include_thumbnail=True)))
|
||||
|
||||
def snapshot(camera, obj: TrackedObject, current_frame_time):
|
||||
mqtt_config = self.config.cameras[camera].mqtt
|
||||
@ -711,8 +714,16 @@ class TrackedObjectProcessor(threading.Thread):
|
||||
self.zone_data = defaultdict(lambda: defaultdict(dict))
|
||||
|
||||
def should_save_snapshot(self, camera, obj: TrackedObject):
|
||||
if obj.false_positive:
|
||||
return False
|
||||
|
||||
snapshot_config: SnapshotsConfig = self.config.cameras[camera].snapshots
|
||||
|
||||
if not snapshot_config.enabled:
|
||||
return False
|
||||
|
||||
# if there are required zones and there is no overlap
|
||||
required_zones = self.config.cameras[camera].snapshots.required_zones
|
||||
required_zones = snapshot_config.required_zones
|
||||
if len(required_zones) > 0 and not obj.entered_zones & set(required_zones):
|
||||
logger.debug(
|
||||
f"Not creating snapshot for {obj.obj_data['id']} because it did not enter required zones"
|
||||
@ -721,6 +732,36 @@ class TrackedObjectProcessor(threading.Thread):
|
||||
|
||||
return True
|
||||
|
||||
def should_retain_recording(self, camera, obj: TrackedObject):
|
||||
if obj.false_positive:
|
||||
return False
|
||||
|
||||
record_config: RecordConfig = self.config.cameras[camera].record
|
||||
|
||||
# Recording is disabled
|
||||
if not record_config.enabled:
|
||||
return False
|
||||
|
||||
# If there are required zones and there is no overlap
|
||||
required_zones = record_config.events.required_zones
|
||||
if len(required_zones) > 0 and not set(obj.entered_zones) & set(required_zones):
|
||||
logger.debug(
|
||||
f"Not creating clip for {obj.obj_data['id']} because it did not enter required zones"
|
||||
)
|
||||
return False
|
||||
|
||||
# If the required objects are not present
|
||||
if (
|
||||
record_config.events.objects is not None
|
||||
and obj.obj_data["label"] not in record_config.events.objects
|
||||
):
|
||||
logger.debug(
|
||||
f"Not creating clip for {obj.obj_data['id']} because it did not contain required objects"
|
||||
)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def should_mqtt_snapshot(self, camera, obj: TrackedObject):
|
||||
# if there are required zones and there is no overlap
|
||||
required_zones = self.config.cameras[camera].mqtt.required_zones
|
||||
@ -815,17 +856,7 @@ class TrackedObjectProcessor(threading.Thread):
|
||||
|
||||
# cleanup event finished queue
|
||||
while not self.event_processed_queue.empty():
|
||||
event_id, camera, clip_created = self.event_processed_queue.get()
|
||||
if clip_created:
|
||||
obj = self.camera_states[camera].tracked_objects[event_id]
|
||||
message = {
|
||||
"before": obj.previous,
|
||||
"after": obj.to_dict(),
|
||||
"type": "clip_ready",
|
||||
}
|
||||
self.client.publish(
|
||||
f"{self.topic_prefix}/events", json.dumps(message), retain=False
|
||||
)
|
||||
event_id, camera = self.event_processed_queue.get()
|
||||
self.camera_states[camera].finished(event_id)
|
||||
|
||||
logger.info(f"Exiting object processor...")
|
||||
|
Loading…
Reference in New Issue
Block a user