mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-15 07:35:27 +03:00
Process subclass for output_frames
This commit is contained in:
parent
09256a4cc8
commit
3badc757cc
@ -13,7 +13,6 @@ from peewee_migrate import Router
|
|||||||
from playhouse.sqlite_ext import SqliteExtDatabase
|
from playhouse.sqlite_ext import SqliteExtDatabase
|
||||||
from playhouse.sqliteq import SqliteQueueDatabase
|
from playhouse.sqliteq import SqliteQueueDatabase
|
||||||
|
|
||||||
from frigate import util
|
|
||||||
from frigate.api.auth import hash_password
|
from frigate.api.auth import hash_password
|
||||||
from frigate.api.fastapi_app import create_fastapi_app
|
from frigate.api.fastapi_app import create_fastapi_app
|
||||||
from frigate.camera.camera import Camera
|
from frigate.camera.camera import Camera
|
||||||
@ -55,7 +54,7 @@ from frigate.models import (
|
|||||||
)
|
)
|
||||||
from frigate.object_detection import ObjectDetectProcess
|
from frigate.object_detection import ObjectDetectProcess
|
||||||
from frigate.object_processing import TrackedObjectProcessor
|
from frigate.object_processing import TrackedObjectProcessor
|
||||||
from frigate.output.output import output_frames
|
from frigate.output.output import OutputProcessor
|
||||||
from frigate.ptz.autotrack import PtzAutoTrackerThread
|
from frigate.ptz.autotrack import PtzAutoTrackerThread
|
||||||
from frigate.ptz.onvif import OnvifController
|
from frigate.ptz.onvif import OnvifController
|
||||||
from frigate.record.cleanup import RecordingCleanup
|
from frigate.record.cleanup import RecordingCleanup
|
||||||
@ -334,15 +333,9 @@ class FrigateApp:
|
|||||||
self.detected_frames_processor.start()
|
self.detected_frames_processor.start()
|
||||||
|
|
||||||
def start_video_output_processor(self) -> None:
|
def start_video_output_processor(self) -> None:
|
||||||
output_processor = util.Process(
|
self.output_processor = OutputProcessor(self.config)
|
||||||
target=output_frames,
|
self.output_processor.start()
|
||||||
name="output_processor",
|
logger.info(f"Output process started: {self.output_processor.pid}")
|
||||||
args=(self.config,),
|
|
||||||
daemon=True,
|
|
||||||
)
|
|
||||||
self.output_processor = output_processor
|
|
||||||
output_processor.start()
|
|
||||||
logger.info(f"Output process started: {output_processor.pid}")
|
|
||||||
|
|
||||||
def init_cameras(self) -> None:
|
def init_cameras(self) -> None:
|
||||||
for name in self.config.cameras.keys():
|
for name in self.config.cameras.keys():
|
||||||
|
|||||||
@ -1,15 +1,11 @@
|
|||||||
"""Handle outputting raw frigate frames"""
|
"""Handle outputting raw frigate frames"""
|
||||||
|
|
||||||
import logging
|
|
||||||
import multiprocessing as mp
|
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import signal
|
|
||||||
import threading
|
import threading
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from wsgiref.simple_server import make_server
|
from wsgiref.simple_server import make_server
|
||||||
|
|
||||||
from setproctitle import setproctitle
|
|
||||||
from ws4py.server.wsgirefserver import (
|
from ws4py.server.wsgirefserver import (
|
||||||
WebSocketWSGIHandler,
|
WebSocketWSGIHandler,
|
||||||
WebSocketWSGIRequestHandler,
|
WebSocketWSGIRequestHandler,
|
||||||
@ -17,6 +13,7 @@ from ws4py.server.wsgirefserver import (
|
|||||||
)
|
)
|
||||||
from ws4py.server.wsgiutils import WebSocketWSGIApplication
|
from ws4py.server.wsgiutils import WebSocketWSGIApplication
|
||||||
|
|
||||||
|
from frigate import util
|
||||||
from frigate.comms.detections_updater import DetectionSubscriber, DetectionTypeEnum
|
from frigate.comms.detections_updater import DetectionSubscriber, DetectionTypeEnum
|
||||||
from frigate.comms.ws import WebSocket
|
from frigate.comms.ws import WebSocket
|
||||||
from frigate.config import FrigateConfig
|
from frigate.config import FrigateConfig
|
||||||
@ -26,23 +23,13 @@ from frigate.output.camera import JsmpegCamera
|
|||||||
from frigate.output.preview import PreviewRecorder
|
from frigate.output.preview import PreviewRecorder
|
||||||
from frigate.util.image import SharedMemoryFrameManager
|
from frigate.util.image import SharedMemoryFrameManager
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
class OutputProcessor(util.Process):
|
||||||
|
def __init__(self, config: FrigateConfig):
|
||||||
|
super().__init__(name="frigate.output", daemon=True)
|
||||||
|
self.config = config
|
||||||
|
|
||||||
def output_frames(
|
def run(self):
|
||||||
config: FrigateConfig,
|
|
||||||
):
|
|
||||||
threading.current_thread().name = "output"
|
|
||||||
setproctitle("frigate.output")
|
|
||||||
|
|
||||||
stop_event = mp.Event()
|
|
||||||
|
|
||||||
def receiveSignal(signalNumber, frame):
|
|
||||||
stop_event.set()
|
|
||||||
|
|
||||||
signal.signal(signal.SIGTERM, receiveSignal)
|
|
||||||
signal.signal(signal.SIGINT, receiveSignal)
|
|
||||||
|
|
||||||
frame_manager = SharedMemoryFrameManager()
|
frame_manager = SharedMemoryFrameManager()
|
||||||
|
|
||||||
# start a websocket server on 8082
|
# start a websocket server on 8082
|
||||||
@ -64,22 +51,24 @@ def output_frames(
|
|||||||
preview_recorders: dict[str, PreviewRecorder] = {}
|
preview_recorders: dict[str, PreviewRecorder] = {}
|
||||||
preview_write_times: dict[str, float] = {}
|
preview_write_times: dict[str, float] = {}
|
||||||
|
|
||||||
move_preview_frames("cache")
|
self.move_preview_frames("cache")
|
||||||
|
|
||||||
for camera, cam_config in config.cameras.items():
|
for camera, cam_config in self.config.cameras.items():
|
||||||
if not cam_config.enabled:
|
if not cam_config.enabled:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
jsmpeg_cameras[camera] = JsmpegCamera(cam_config, stop_event, websocket_server)
|
jsmpeg_cameras[camera] = JsmpegCamera(
|
||||||
|
cam_config, self.stop_event, websocket_server
|
||||||
|
)
|
||||||
preview_recorders[camera] = PreviewRecorder(cam_config)
|
preview_recorders[camera] = PreviewRecorder(cam_config)
|
||||||
preview_write_times[camera] = 0
|
preview_write_times[camera] = 0
|
||||||
|
|
||||||
if config.birdseye.enabled:
|
if self.config.birdseye.enabled:
|
||||||
birdseye = Birdseye(config, stop_event, websocket_server)
|
birdseye = Birdseye(self.config, self.stop_event, websocket_server)
|
||||||
|
|
||||||
websocket_thread.start()
|
websocket_thread.start()
|
||||||
|
|
||||||
while not stop_event.is_set():
|
while not self.stop_event.is_set():
|
||||||
(topic, data) = detection_subscriber.check_for_update(timeout=1)
|
(topic, data) = detection_subscriber.check_for_update(timeout=1)
|
||||||
|
|
||||||
if not topic:
|
if not topic:
|
||||||
@ -95,22 +84,25 @@ def output_frames(
|
|||||||
|
|
||||||
frame_id = f"{camera}{frame_time}"
|
frame_id = f"{camera}{frame_time}"
|
||||||
|
|
||||||
frame = frame_manager.get(frame_id, config.cameras[camera].frame_shape_yuv)
|
frame = frame_manager.get(
|
||||||
|
frame_id, self.config.cameras[camera].frame_shape_yuv
|
||||||
|
)
|
||||||
|
|
||||||
if frame is None:
|
if frame is None:
|
||||||
logger.debug(f"Failed to get frame {frame_id} from SHM")
|
self.logger.debug(f"Failed to get frame {frame_id} from SHM")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# send camera frame to ffmpeg process if websockets are connected
|
# send camera frame to ffmpeg process if websockets are connected
|
||||||
if any(
|
if any(
|
||||||
ws.environ["PATH_INFO"].endswith(camera) for ws in websocket_server.manager
|
ws.environ["PATH_INFO"].endswith(camera)
|
||||||
|
for ws in websocket_server.manager
|
||||||
):
|
):
|
||||||
# write to the converter for the camera if clients are listening to the specific camera
|
# write to the converter for the camera if clients are listening to the specific camera
|
||||||
jsmpeg_cameras[camera].write_frame(frame.tobytes())
|
jsmpeg_cameras[camera].write_frame(frame.tobytes())
|
||||||
|
|
||||||
# send output data to birdseye if websocket is connected or restreaming
|
# send output data to birdseye if websocket is connected or restreaming
|
||||||
if config.birdseye.enabled and (
|
if self.config.birdseye.enabled and (
|
||||||
config.birdseye.restream
|
self.config.birdseye.restream
|
||||||
or any(
|
or any(
|
||||||
ws.environ["PATH_INFO"].endswith("birdseye")
|
ws.environ["PATH_INFO"].endswith("birdseye")
|
||||||
for ws in websocket_server.manager
|
for ws in websocket_server.manager
|
||||||
@ -141,7 +133,7 @@ def output_frames(
|
|||||||
|
|
||||||
frame_manager.close(frame_id)
|
frame_manager.close(frame_id)
|
||||||
|
|
||||||
move_preview_frames("clips")
|
self.move_preview_frames("clips")
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
(topic, data) = detection_subscriber.check_for_update(timeout=0)
|
(topic, data) = detection_subscriber.check_for_update(timeout=0)
|
||||||
@ -158,7 +150,9 @@ def output_frames(
|
|||||||
) = data
|
) = data
|
||||||
|
|
||||||
frame_id = f"{camera}{frame_time}"
|
frame_id = f"{camera}{frame_time}"
|
||||||
frame = frame_manager.get(frame_id, config.cameras[camera].frame_shape_yuv)
|
frame = frame_manager.get(
|
||||||
|
frame_id, self.config.cameras[camera].frame_shape_yuv
|
||||||
|
)
|
||||||
frame_manager.close(frame_id)
|
frame_manager.close(frame_id)
|
||||||
|
|
||||||
detection_subscriber.stop()
|
detection_subscriber.stop()
|
||||||
@ -177,10 +171,9 @@ def output_frames(
|
|||||||
websocket_server.manager.join()
|
websocket_server.manager.join()
|
||||||
websocket_server.shutdown()
|
websocket_server.shutdown()
|
||||||
websocket_thread.join()
|
websocket_thread.join()
|
||||||
logger.info("exiting output process...")
|
self.logger.info("Exiting output process...")
|
||||||
|
|
||||||
|
def move_preview_frames(self, loc: str):
|
||||||
def move_preview_frames(loc: str):
|
|
||||||
preview_holdover = os.path.join(CLIPS_DIR, "preview_restart_cache")
|
preview_holdover = os.path.join(CLIPS_DIR, "preview_restart_cache")
|
||||||
preview_cache = os.path.join(CACHE_DIR, "preview_frames")
|
preview_cache = os.path.join(CACHE_DIR, "preview_frames")
|
||||||
|
|
||||||
@ -193,4 +186,4 @@ def move_preview_frames(loc: str):
|
|||||||
|
|
||||||
shutil.move(preview_holdover, preview_cache)
|
shutil.move(preview_holdover, preview_cache)
|
||||||
except shutil.Error:
|
except shutil.Error:
|
||||||
logger.error("Failed to restore preview cache.")
|
self.logger.error("Failed to restore preview cache.")
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user