Browse Source

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.
Sean Vig 4 years ago
parent
commit
a4e6d9ed9a
3 changed files with 50 additions and 64 deletions
  1. 21 26
      frigate/events.py
  2. 12 16
      frigate/process_clip.py
  3. 17 22
      frigate/record.py

+ 21 - 26
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"
-            )
-
-            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())
+            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 = [
+                "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"]:

+ 12 - 16
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]
 

+ 17 - 22
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"
-            )
-
-            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())
+            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 = [
+                "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))