mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-02 09:15:22 +03:00
recording for GStreamer
This commit is contained in:
parent
d5dd82fa47
commit
1aa6ccaa6d
@ -12,7 +12,7 @@ import yaml
|
||||
from pydantic import BaseModel, Extra, Field, validator, root_validator
|
||||
from pydantic.fields import PrivateAttr
|
||||
|
||||
from frigate.const import BASE_DIR, CACHE_DIR, YAML_EXT
|
||||
from frigate.const import BASE_DIR, CACHE_DIR, YAML_EXT, RECORD_SEGMENT_TIME_SECONDS
|
||||
from frigate.util import (
|
||||
create_mask,
|
||||
deep_merge,
|
||||
@ -315,7 +315,7 @@ RECORD_FFMPEG_OUTPUT_ARGS_DEFAULT = [
|
||||
"-f",
|
||||
"segment",
|
||||
"-segment_time",
|
||||
"10",
|
||||
str(RECORD_SEGMENT_TIME_SECONDS),
|
||||
"-segment_format",
|
||||
"mp4",
|
||||
"-reset_timestamps",
|
||||
@ -616,7 +616,7 @@ class CameraConfig(FrigateBaseModel):
|
||||
)
|
||||
|
||||
builder = GstreamerBuilder(
|
||||
gstreamer_input.path, self.detect.width, self.detect.height
|
||||
gstreamer_input.path, self.detect.width, self.detect.height, self.name
|
||||
)
|
||||
if caps is None or len(caps) == 0:
|
||||
logger.warn("gsreamer was not able to detect the input stream format")
|
||||
|
||||
@ -3,3 +3,5 @@ CLIPS_DIR = f"{BASE_DIR}/clips"
|
||||
RECORD_DIR = f"{BASE_DIR}/recordings"
|
||||
CACHE_DIR = "/tmp/cache"
|
||||
YAML_EXT = (".yaml", ".yml")
|
||||
RECORD_SEGMENT_TIME_SECONDS = 10
|
||||
GSTREAMER_RECORD_SUFFIX = "-gstsplitmuxchunk"
|
||||
|
||||
@ -3,7 +3,11 @@ import logging
|
||||
import traceback
|
||||
import subprocess as sp
|
||||
from typing import Dict, List, Optional
|
||||
from frigate.const import CACHE_DIR
|
||||
from frigate.const import (
|
||||
CACHE_DIR,
|
||||
GSTREAMER_RECORD_SUFFIX,
|
||||
RECORD_SEGMENT_TIME_SECONDS,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -62,6 +66,7 @@ def gst_inspect_find_codec(codec: str) -> List[str]:
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
def autodetect_decoder_pipeline(
|
||||
codec: Optional[str],
|
||||
) -> List[str]:
|
||||
@ -118,10 +123,11 @@ CODECS = {
|
||||
|
||||
|
||||
class GstreamerBuilder:
|
||||
def __init__(self, uri, width, height, format="I420"):
|
||||
def __init__(self, uri, width, height, name, format="I420"):
|
||||
self.uri = uri
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.name = name
|
||||
self.video_format = f"video/x-raw,width=(int){width},height=(int){height},format=(string){format}"
|
||||
self.input_pipeline = [f'rtspsrc location="{uri}" latency=0']
|
||||
self.destination_format_pipeline = [self.video_format, "videoconvert"]
|
||||
@ -141,7 +147,7 @@ class GstreamerBuilder:
|
||||
|
||||
self.decoder_pipeline = autodetect_decoder_pipeline(codec)
|
||||
return self
|
||||
|
||||
|
||||
def with_source_format_pipeline(self, source_format_pipeline):
|
||||
source_format_pipeline = (
|
||||
source_format_pipeline
|
||||
@ -176,7 +182,7 @@ class GstreamerBuilder:
|
||||
"queue2",
|
||||
"x264enc key-int-max=10",
|
||||
"h264parse",
|
||||
f"splitmuxsink async-handling=true location={os.path.join(CACHE_DIR, self.name)}-gst-%05d.mp4 max-size-time=10000000000",
|
||||
f"splitmuxsink async-handling=true location={os.path.join(CACHE_DIR, self.name)}{GSTREAMER_RECORD_SUFFIX}-%05d.mp4 max-size-time={RECORD_SEGMENT_TIME_SECONDS*1000000000}",
|
||||
]
|
||||
if use_record
|
||||
else []
|
||||
@ -188,4 +194,3 @@ class GstreamerBuilder:
|
||||
]
|
||||
pipeline_args = [item for sublist in pipeline_args for item in sublist]
|
||||
return ["gst-launch-1.0", "-q", *pipeline_args][:-1]
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import datetime
|
||||
from dateutil import tz
|
||||
import itertools
|
||||
import logging
|
||||
import multiprocessing as mp
|
||||
@ -17,7 +18,12 @@ import psutil
|
||||
from peewee import JOIN, DoesNotExist
|
||||
|
||||
from frigate.config import RetainModeEnum, FrigateConfig
|
||||
from frigate.const import CACHE_DIR, RECORD_DIR
|
||||
from frigate.const import (
|
||||
CACHE_DIR,
|
||||
RECORD_DIR,
|
||||
GSTREAMER_RECORD_SUFFIX,
|
||||
RECORD_SEGMENT_TIME_SECONDS,
|
||||
)
|
||||
from frigate.models import Event, Recordings
|
||||
from frigate.util import area
|
||||
|
||||
@ -69,7 +75,7 @@ class RecordingMaintainer(threading.Thread):
|
||||
files_in_use = []
|
||||
for process in psutil.process_iter():
|
||||
try:
|
||||
if process.name() != "ffmpeg":
|
||||
if process.name() not in ["ffmpeg", "gst-launch-1.0"]:
|
||||
continue
|
||||
flist = process.open_files()
|
||||
if flist:
|
||||
@ -89,7 +95,14 @@ class RecordingMaintainer(threading.Thread):
|
||||
cache_path = os.path.join(CACHE_DIR, f)
|
||||
basename = os.path.splitext(f)[0]
|
||||
camera, date = basename.rsplit("-", maxsplit=1)
|
||||
start_time = datetime.datetime.strptime(date, "%Y%m%d%H%M%S")
|
||||
if camera.endswith(GSTREAMER_RECORD_SUFFIX):
|
||||
camera = camera.split(GSTREAMER_RECORD_SUFFIX)[0]
|
||||
creation_time = (
|
||||
os.path.getmtime(cache_path) - RECORD_SEGMENT_TIME_SECONDS
|
||||
)
|
||||
start_time = datetime.datetime.utcfromtimestamp(creation_time)
|
||||
else:
|
||||
start_time = datetime.datetime.strptime(date, "%Y%m%d%H%M%S")
|
||||
|
||||
grouped_recordings[camera].append(
|
||||
{
|
||||
|
||||
Loading…
Reference in New Issue
Block a user