From a4e6d9ed9a85e0bd9e5a712b9c4c67131e43c77c Mon Sep 17 00:00:00 2001 From: Sean Vig Date: Fri, 21 May 2021 23:35:25 -0400 Subject: [PATCH] Improve ffprobe executions When running ffprobe, use `subprocess.run` rather than `subprocess.Popen`. This simplifies the handling that is needed to run and process the outputs. Here, filename parsing is also simplified by explicitly removing the file extension with `os.path.splitext` and forcing a single split into the camera name and the formatted date. --- frigate/events.py | 45 ++++++++++++++++++----------------------- frigate/process_clip.py | 28 +++++++++++-------------- frigate/record.py | 37 +++++++++++++++------------------ 3 files changed, 48 insertions(+), 62 deletions(-) diff --git a/frigate/events.py b/frigate/events.py index 93ea7f87a..b1e666d7c 100644 --- a/frigate/events.py +++ b/frigate/events.py @@ -72,28 +72,23 @@ class EventProcessor(threading.Thread): if f in files_in_use or f in self.cached_clips: continue - camera = "-".join(f.split("-")[:-1]) - start_time = datetime.datetime.strptime( - f.split("-")[-1].split(".")[0], "%Y%m%d%H%M%S" - ) + basename = os.path.splitext(f)[0] + camera, date = basename.rsplit("-", maxsplit=1) + start_time = datetime.datetime.strptime(date, "%Y%m%d%H%M%S") - ffprobe_cmd = " ".join( - [ - "ffprobe", - "-v", - "error", - "-show_entries", - "format=duration", - "-of", - "default=noprint_wrappers=1:nokey=1", - f"{os.path.join(CACHE_DIR,f)}", - ] - ) - p = sp.Popen(ffprobe_cmd, stdout=sp.PIPE, shell=True) - (output, err) = p.communicate() - p_status = p.wait() - if p_status == 0: - duration = float(output.decode("utf-8").strip()) + ffprobe_cmd = [ + "ffprobe", + "-v", + "error", + "-show_entries", + "format=duration", + "-of", + "default=noprint_wrappers=1:nokey=1", + f"{os.path.join(CACHE_DIR, f)}", + ] + p = sp.run(ffprobe_cmd, capture_output=True) + if p.returncode == 0: + duration = float(p.stdout.decode().strip()) else: logger.info(f"bad file: {f}") os.remove(os.path.join(CACHE_DIR, f)) @@ -113,10 +108,10 @@ class EventProcessor(threading.Thread): else: earliest_event = datetime.datetime.now().timestamp() - # if the earliest event exceeds the max seconds, cap it - max_seconds = self.config.clips.max_seconds - if datetime.datetime.now().timestamp() - earliest_event > max_seconds: - earliest_event = datetime.datetime.now().timestamp() - max_seconds + # if the earliest event is more tha max seconds ago, cap it + earliest_event = max( + earliest_event, datetime.datetime.now().timestamp() - max_seconds + ) for f, data in list(self.cached_clips.items()): if earliest_event - 90 > data["start_time"] + data["duration"]: diff --git a/frigate/process_clip.py b/frigate/process_clip.py index 685dade04..b6462121c 100644 --- a/frigate/process_clip.py +++ b/frigate/process_clip.py @@ -31,22 +31,18 @@ logger = logging.getLogger(__name__) def get_frame_shape(source): - ffprobe_cmd = " ".join( - [ - "ffprobe", - "-v", - "panic", - "-show_error", - "-show_streams", - "-of", - "json", - '"' + source + '"', - ] - ) - p = sp.Popen(ffprobe_cmd, stdout=sp.PIPE, shell=True) - (output, err) = p.communicate() - p_status = p.wait() - info = json.loads(output) + ffprobe_cmd = [ + "ffprobe", + "-v", + "panic", + "-show_error", + "-show_streams", + "-of", + "json", + source, + ] + p = sp.run(ffprobe_cmd, capture_output=True) + info = json.loads(p.stdout) video_info = [s for s in info["streams"] if s["codec_type"] == "video"][0] diff --git a/frigate/record.py b/frigate/record.py index 496230a58..ea2593ca0 100644 --- a/frigate/record.py +++ b/frigate/record.py @@ -66,28 +66,23 @@ class RecordingMaintainer(threading.Thread): if f in files_in_use: continue - camera = "-".join(f.split("-")[:-1]) - start_time = datetime.datetime.strptime( - f.split("-")[-1].split(".")[0], "%Y%m%d%H%M%S" - ) + basename = os.path.splitext(f)[0] + camera, date = basename.rsplit("-", maxsplit=1) + start_time = datetime.datetime.strptime(date, "%Y%m%d%H%M%S") - ffprobe_cmd = " ".join( - [ - "ffprobe", - "-v", - "error", - "-show_entries", - "format=duration", - "-of", - "default=noprint_wrappers=1:nokey=1", - f"{os.path.join(RECORD_DIR,f)}", - ] - ) - p = sp.Popen(ffprobe_cmd, stdout=sp.PIPE, shell=True) - (output, err) = p.communicate() - p_status = p.wait() - if p_status == 0: - duration = float(output.decode("utf-8").strip()) + ffprobe_cmd = [ + "ffprobe", + "-v", + "error", + "-show_entries", + "format=duration", + "-of", + "default=noprint_wrappers=1:nokey=1", + f"{os.path.join(RECORD_DIR, f)}", + ] + p = sp.run(ffprobe_cmd, capture_output=True) + if p.returncode == 0: + duration = float(p.stdout.decode().strip()) else: logger.info(f"bad file: {f}") os.remove(os.path.join(RECORD_DIR, f))