mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-05 18:55:23 +03:00
Save event to db
This commit is contained in:
parent
b5acd6a287
commit
734eb07a23
126
frigate/audio.py
126
frigate/audio.py
@ -1,126 +0,0 @@
|
|||||||
import datetime
|
|
||||||
import logging
|
|
||||||
import multiprocessing as mp
|
|
||||||
import queue
|
|
||||||
import random
|
|
||||||
import signal
|
|
||||||
import string
|
|
||||||
import threading
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
from setproctitle import setproctitle
|
|
||||||
|
|
||||||
from frigate.config import CameraConfig, AudioModelConfig
|
|
||||||
from frigate.object_detection import RemoteObjectDetector
|
|
||||||
from frigate.util import listen, SharedMemoryFrameManager
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
def capture_audio(
|
|
||||||
name: str,
|
|
||||||
model_config: AudioModelConfig,
|
|
||||||
process_info,
|
|
||||||
):
|
|
||||||
stop_event = mp.Event()
|
|
||||||
|
|
||||||
def receiveSignal(signalNumber, frame):
|
|
||||||
stop_event.set()
|
|
||||||
|
|
||||||
signal.signal(signal.SIGTERM, receiveSignal)
|
|
||||||
signal.signal(signal.SIGINT, receiveSignal)
|
|
||||||
|
|
||||||
threading.current_thread().name = f"capture:{name}"
|
|
||||||
setproctitle(f"frigate.capture:{name}")
|
|
||||||
listen()
|
|
||||||
|
|
||||||
chunk_size = int(round(model_config.duration * model_config.sample_rate * 2))
|
|
||||||
|
|
||||||
key = f"{name}-audio"
|
|
||||||
|
|
||||||
audio_queue = process_info["audio_queue"]
|
|
||||||
frame_manager = SharedMemoryFrameManager()
|
|
||||||
current_frame = mp.Value("d", 0.0)
|
|
||||||
|
|
||||||
pipe = open(f"/tmp/{key}", "rb")
|
|
||||||
|
|
||||||
while not stop_event.is_set():
|
|
||||||
current_frame.value = datetime.datetime.now().timestamp()
|
|
||||||
frame_name = f"{key}{current_frame.value}"
|
|
||||||
frame_buffer = frame_manager.create(frame_name, chunk_size)
|
|
||||||
|
|
||||||
try:
|
|
||||||
frame_buffer[:] = pipe.read(chunk_size)
|
|
||||||
except Exception as e:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# if the queue is full, skip this frame
|
|
||||||
if audio_queue.full():
|
|
||||||
frame_manager.delete(frame_name)
|
|
||||||
continue
|
|
||||||
|
|
||||||
# close the frame
|
|
||||||
frame_manager.close(frame_name)
|
|
||||||
|
|
||||||
# add to the queue
|
|
||||||
audio_queue.put(current_frame.value)
|
|
||||||
|
|
||||||
|
|
||||||
def process_audio(
|
|
||||||
name: str,
|
|
||||||
camera_config: CameraConfig,
|
|
||||||
model_config: AudioModelConfig,
|
|
||||||
labelmap,
|
|
||||||
detection_queue: mp.Queue,
|
|
||||||
result_connection,
|
|
||||||
process_info,
|
|
||||||
):
|
|
||||||
stop_event = mp.Event()
|
|
||||||
|
|
||||||
def receiveSignal(signalNumber, frame):
|
|
||||||
stop_event.set()
|
|
||||||
|
|
||||||
signal.signal(signal.SIGTERM, receiveSignal)
|
|
||||||
signal.signal(signal.SIGINT, receiveSignal)
|
|
||||||
|
|
||||||
threading.current_thread().name = f"process:{name}"
|
|
||||||
setproctitle(f"frigate.process:{name}")
|
|
||||||
listen()
|
|
||||||
|
|
||||||
shape = (int(round(model_config.duration * model_config.sample_rate)),)
|
|
||||||
|
|
||||||
key = f"{name}-audio"
|
|
||||||
|
|
||||||
audio_queue = process_info["audio_queue"]
|
|
||||||
frame_manager = SharedMemoryFrameManager()
|
|
||||||
|
|
||||||
detector = RemoteObjectDetector(
|
|
||||||
key, labelmap, detection_queue, result_connection, model_config
|
|
||||||
)
|
|
||||||
|
|
||||||
while not stop_event.is_set():
|
|
||||||
try:
|
|
||||||
frame_time = audio_queue.get(True, 10)
|
|
||||||
except queue.Empty:
|
|
||||||
continue
|
|
||||||
|
|
||||||
audio = frame_manager.get(f"{key}{frame_time}", shape, dtype=np.int16)
|
|
||||||
|
|
||||||
if audio is None:
|
|
||||||
logger.info(f"{key}: audio {frame_time} is not in memory store.")
|
|
||||||
continue
|
|
||||||
|
|
||||||
waveform = (audio / 32768.0).astype(np.float32)
|
|
||||||
model_detections = detector.detect(waveform)
|
|
||||||
|
|
||||||
for label, score, _ in model_detections:
|
|
||||||
if label not in camera_config.objects.track:
|
|
||||||
continue
|
|
||||||
filters = camera_config.objects.filters.get(label)
|
|
||||||
if filters:
|
|
||||||
if score < filters.min_score:
|
|
||||||
continue
|
|
||||||
logger.info(f"{label}: {score}")
|
|
||||||
|
|
||||||
frame_manager.close(f"{key}{frame_time}")
|
|
||||||
@ -1,10 +1,13 @@
|
|||||||
"""Handle creating audio events."""
|
"""Handle creating audio events."""
|
||||||
|
|
||||||
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
import multiprocessing as mp
|
import multiprocessing as mp
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import os
|
import os
|
||||||
|
import random
|
||||||
import signal
|
import signal
|
||||||
|
import string
|
||||||
import subprocess as sp
|
import subprocess as sp
|
||||||
import threading
|
import threading
|
||||||
from types import FrameType
|
from types import FrameType
|
||||||
@ -20,6 +23,7 @@ from frigate.const import (
|
|||||||
AUDIO_SAMPLE_RATE,
|
AUDIO_SAMPLE_RATE,
|
||||||
CACHE_DIR,
|
CACHE_DIR,
|
||||||
)
|
)
|
||||||
|
from frigate.events.maintainer import EventTypeEnum
|
||||||
from frigate.ffmpeg_presets import parse_preset_input
|
from frigate.ffmpeg_presets import parse_preset_input
|
||||||
from frigate.object_detection import load_labels
|
from frigate.object_detection import load_labels
|
||||||
from frigate.util import get_ffmpeg_arg_list, listen
|
from frigate.util import get_ffmpeg_arg_list, listen
|
||||||
@ -51,7 +55,7 @@ def listen_to_audio(config: FrigateConfig, event_queue: mp.Queue) -> None:
|
|||||||
|
|
||||||
for camera in config.cameras.values():
|
for camera in config.cameras.values():
|
||||||
if camera.enabled and camera.audio.enabled:
|
if camera.enabled and camera.audio.enabled:
|
||||||
AudioEventMaintainer(camera, stop_event).start()
|
AudioEventMaintainer(camera, event_queue, stop_event).start()
|
||||||
|
|
||||||
|
|
||||||
class AudioTfl:
|
class AudioTfl:
|
||||||
@ -110,10 +114,12 @@ class AudioTfl:
|
|||||||
|
|
||||||
|
|
||||||
class AudioEventMaintainer(threading.Thread):
|
class AudioEventMaintainer(threading.Thread):
|
||||||
def __init__(self, camera: CameraConfig, stop_event: mp.Event) -> None:
|
def __init__(self, camera: CameraConfig, event_queue: mp.Queue, stop_event: mp.Event) -> None:
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
self.name = f"{camera.name}_audio_event_processor"
|
self.name = f"{camera.name}_audio_event_processor"
|
||||||
self.config = camera
|
self.config = camera
|
||||||
|
self.queue = event_queue
|
||||||
|
self.detections: dict[dict[str, any]] = {}
|
||||||
self.stop_event = stop_event
|
self.stop_event = stop_event
|
||||||
self.detector = AudioTfl()
|
self.detector = AudioTfl()
|
||||||
self.shape = (int(round(AUDIO_DURATION * AUDIO_SAMPLE_RATE)),)
|
self.shape = (int(round(AUDIO_DURATION * AUDIO_SAMPLE_RATE)),)
|
||||||
@ -140,8 +146,24 @@ class AudioEventMaintainer(threading.Thread):
|
|||||||
if label not in self.config.audio.listen:
|
if label not in self.config.audio.listen:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
logger.error(f"Detected audio: {label} with score {score}")
|
self.handle_detection(label, score)
|
||||||
# TODO handle valid detect
|
|
||||||
|
def handle_detection(self, label: str, score: float) -> None:
|
||||||
|
if self.detections[label] is not None:
|
||||||
|
self.detections[label]["last_detection"] = datetime.datetime.now().timestamp()
|
||||||
|
else:
|
||||||
|
now = datetime.datetime.now().timestamp()
|
||||||
|
rand_id = "".join(random.choices(string.ascii_lowercase + string.digits, k=6))
|
||||||
|
event_id = f"{now}-{rand_id}"
|
||||||
|
self.detections[label] = {
|
||||||
|
"id": event_id,
|
||||||
|
"label": label,
|
||||||
|
"camera": self.config.name,
|
||||||
|
"start_time": now,
|
||||||
|
"last_detection": now,
|
||||||
|
}
|
||||||
|
self.queue.put((EventTypeEnum.audio, "start", self.config.name, self.detections[label]))
|
||||||
|
|
||||||
|
|
||||||
def init_ffmpeg(self) -> None:
|
def init_ffmpeg(self) -> None:
|
||||||
try:
|
try:
|
||||||
|
|||||||
@ -17,7 +17,7 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
class EventTypeEnum(str, Enum):
|
class EventTypeEnum(str, Enum):
|
||||||
api = "api"
|
api = "api"
|
||||||
# audio = "audio"
|
audio = "audio"
|
||||||
tracked_object = "tracked_object"
|
tracked_object = "tracked_object"
|
||||||
|
|
||||||
|
|
||||||
@ -90,6 +90,8 @@ class EventProcessor(threading.Thread):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
self.handle_object_detection(event_type, camera, event_data)
|
self.handle_object_detection(event_type, camera, event_data)
|
||||||
|
elif source_type == EventTypeEnum.audio:
|
||||||
|
self.handle_audio_detection(event_type, camera, event_data)
|
||||||
elif source_type == EventTypeEnum.api:
|
elif source_type == EventTypeEnum.api:
|
||||||
self.handle_external_detection(event_type, event_data)
|
self.handle_external_detection(event_type, event_data)
|
||||||
|
|
||||||
@ -214,7 +216,35 @@ class EventProcessor(threading.Thread):
|
|||||||
del self.events_in_process[event_data["id"]]
|
del self.events_in_process[event_data["id"]]
|
||||||
self.event_processed_queue.put((event_data["id"], camera))
|
self.event_processed_queue.put((event_data["id"], camera))
|
||||||
|
|
||||||
def handle_external_detection(self, type: str, event_data: Event):
|
def handle_audio_detection(self, type: str, event_data: Event) -> None:
|
||||||
|
if type == "new":
|
||||||
|
event = {
|
||||||
|
Event.id: event_data["id"],
|
||||||
|
Event.label: event_data["label"],
|
||||||
|
Event.camera: event_data["camera"],
|
||||||
|
Event.start_time: event_data["start_time"],
|
||||||
|
Event.thumbnail: None,
|
||||||
|
Event.has_clip: True,
|
||||||
|
Event.has_snapshot: True,
|
||||||
|
Event.zones: [],
|
||||||
|
Event.data: {},
|
||||||
|
}
|
||||||
|
elif type == "end":
|
||||||
|
event = {
|
||||||
|
Event.id: event_data["id"],
|
||||||
|
Event.end_time: event_data["end_time"],
|
||||||
|
}
|
||||||
|
|
||||||
|
(
|
||||||
|
Event.insert(event)
|
||||||
|
.on_conflict(
|
||||||
|
conflict_target=[Event.id],
|
||||||
|
update=event,
|
||||||
|
)
|
||||||
|
.execute()
|
||||||
|
)
|
||||||
|
|
||||||
|
def handle_external_detection(self, type: str, event_data: Event) -> None:
|
||||||
if type == "new":
|
if type == "new":
|
||||||
event = {
|
event = {
|
||||||
Event.id: event_data["id"],
|
Event.id: event_data["id"],
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user